Potato的暑期训练day#2 ——图论之拓扑排序
题目链接:
A.http://poj.org/problem?id=2585
B.http://poj.org/problem?id=1270
C.http://poj.org/problem?id=1094
D.http://poj.org/problem?id=3687
A.Window Pains
题意:已知一个4*4的方格和各方格可能出现的数字,给出一个方格当前的显示,求出达到当前情况所需要的方格覆盖次序。
思路:先打出各个方格可能出现数字的表,然后根据当前方格的数字来确定该数在哪些数的上面,与之连边建立有向图拓扑排序即可。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N = 4;
int G[N][N];
int deg[9],s;
vector<int> F[N*N];
int PO[9][9];
void init() {
F[0].push_back(1);
F[1].push_back(1);F[1].push_back(2);
F[2].push_back(2);F[2].push_back(3);
F[3].push_back(3);
F[4].push_back(1);F[4].push_back(4);
F[5].push_back(1);F[5].push_back(2);F[5].push_back(4);F[5].push_back(5);
F[6].push_back(2);F[6].push_back(3);F[6].push_back(5);F[6].push_back(6);
F[7].push_back(3);F[7].push_back(6);
F[8].push_back(4);F[8].push_back(7);
F[9].push_back(4);F[9].push_back(5);F[9].push_back(7);F[9].push_back(8);
F[10].push_back(5);F[10].push_back(6);F[10].push_back(8);F[10].push_back(9);
F[11].push_back(6);F[11].push_back(9);
F[12].push_back(7);
F[13].push_back(7);F[13].push_back(8);
F[14].push_back(8);F[14].push_back(9);
F[15].push_back(9);
}
bool top(int s) {
int flag = 0;
queue<int> Q;
while(!Q.empty()) Q.pop();
for(int i = 0;i < 9;i++) {
if(deg[i] == 0) Q.push(i);
}
while(!Q.empty()) {
int u = Q.front();Q.pop();
for(int i = 0;i < 9;i++) {
if(PO[u][i]) {
deg[i]--;
s--;
if(!deg[i]) {
Q.push(i);
}
}
}
}
if(s == 0) return true;
else return false;
}
bool solve() {
for(int i = 0;i < N;i++) {
for(int j = 0;j < N;j++) {
int u = N * i + j,v = G[i][j];
for(int k = 0;k < F[u].size();k++) {
if(F[u][k] != v) {
if(PO[v-1][F[u][k]-1] == 0){
deg[F[u][k]-1]++;
PO[v-1][F[u][k]-1] = 1;
s++;
}
}
}
}
}
/*for(int i = 0;i < 9;i++) {
for(int j = 0;j < 9;j++) {
printf("%d ",PO[i][j]);
}
printf("
");
}*/
//printf("%d
",s);
if(top(s)) return true;
else return false;
}
int main() {
char str[20];
init();
for(;;) {
scanf("%s",str);
if(strlen(str) > 3 && str[3] == 'O') break;
memset(deg,0,sizeof(deg));
memset(PO,0,sizeof(PO));
s = 0;
for(int i = 0;i < N;i++)
for(int j = 0;j < N;j++)
scanf("%d",&G[i][j]);
if(solve()) printf("THESE WINDOWS ARE CLEAN
");
else printf("THESE WINDOWS ARE BROKEN
");
scanf("%s",str);
}
return 0;
}
B.Following Orders
题意:给定变量之间形如x<y的约束关系列表,要求按字典序输出满足约束关系的所有变量序列
思路:由于要输出所有满足约束关系的序列,所以使用dfs回溯的方法优先搜索字典序小的
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctype.h>
#include<map>
using namespace std;
char s[100];
char tt[30];
int G[30][30];
int deg[30];
int cnt,cur;
char ans[30];
map<char,int> mp;
void topsort(int depth) {
if(depth == cnt) {printf("%s
",ans);return ;}
for(int i = 0;i < cnt;i++) {
if(deg[i] == 0) {ans[depth] = tt[i];
--deg[i];
for(int j = 0;j < cnt;j++) {
if(G[i][j]) deg[j]--;
}
topsort(depth+1);
++deg[i];
for(int j = 0;j < cnt;j++) {
if(G[i][j]) deg[j]++;
}
}}
}
int main() {
for(;;) {
gets(s);
int len = strlen(s);
if(len == 0) break;
cnt = 0;
memset(tt,0,sizeof(tt));
memset(G,0,sizeof(G));
memset(deg,0,sizeof(deg));
memset(ans,0,sizeof(ans));
for(int i = 0;i < len;i++) {
if(isalpha(s[i])) {
tt[cnt++] = s[i];
}
}
sort(tt,tt+cnt);
for(int i = 0;i < cnt;i++) {
mp[tt[i]] = i;
}
memset(s,0,sizeof(s));
gets(s);
len = strlen(s);
if(len == 0) break;
int flag = 0;
int u,v;
for(int i = 0;i < len;i++) {
if(isalpha(s[i]) && !flag) {
u = mp[s[i]];
flag = 1;
}
else if(isalpha(s[i]) && flag) {
v = mp[s[i]];
flag = 0;
G[u][v] = 1;
deg[v]++;
}
}
topsort(0);
printf("
");
}
return 0;
}
C.Sorting It All Out
题意:将需要拓扑排序的边一条一条的给你,让你判断是否可以确定这个序列只有一种情况,还是有多种情况,还是有环。
思路:bfs判断是否有环,维护入度为0的点的时候,观察是否存在超过1的情况。
代码:
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 27;
int n,m;
vector<int> G[maxn];
int in[maxn],deg[maxn];
char ans[maxn];
int cnt;
void init() {
for(int i = 0;i < n;i++) G[i].clear();
memset(in,0,sizeof(in));
}
bool check(int u,int v) {
for(int i = 0;i < G[u].size();i++) if(G[u][i] == v) return true;
return false;
}
//传入当前边数
int topsort() {
for(int i = 0;i < n;i++) deg[i] = in[i];
cnt = 0;
int flag = 1;
memset(ans,0,sizeof(ans));
queue<int> Q;
while(!Q.empty()) Q.pop();
for(int i = 0;i < n;i++) {
if(deg[i] == 0) Q.push(i);
}
//if(Q.size() > 1) flag = 0; !!!判断是否有多种情况
while(!Q.empty()) {
if(Q.size() > 1) flag = 0;
int u = Q.front();Q.pop();
ans[cnt++] = u + 'A';
int len = G[u].size();
for(int i = 0;i < len;i++) {
int v = G[u][i];
deg[v]--;
if(deg[v] == 0) {
Q.push(v);
}
}
}
if(cnt < n) return 2;
else if(cnt == n && flag) return 3;
else return 1;
}
int main() {
while(scanf("%d%d",&n,&m) == 2) {
if(n == 0 && m == 0) break;
init();
char s[5];
int flag,ok = 0,k;
for(int i = 0;i < m;i++) {
scanf("%s",s);
if(ok) continue;
int u = s[0] - 'A',v = s[2] - 'A';
if(check(u,v)) continue;
in[v]++;
G[u].push_back(v);
flag = topsort();
if(flag == 3) {
ok = 1;
printf("Sorted sequence determined after %d relations: %s.
",i+1,ans);
}
else if(flag == 2) {
ok = 1;
printf("Inconsistency found after %d relations.
",i+1);
}
}
if(flag == 1) printf("Sorted sequence cannot be determined.
");
}
return 0;
}
D.Labeling Balls
题意:有N个不同质量的球,重量为1~N,现在满足一些约束(类似于编号a的球比b的轻) 来给这些球贴1-N的标签,如果有多种情况要保证序号小的球质量轻。
思路:我们先考虑对位置的排序,我们按照1,2,3...N的质量来放球,我们要调整位置的排序使之满足,比如说我们有a<b,从c<d那么我们要保证a的位置在b前面(c,d同理),其次我们要满足序号小的尽量要小,我们放置a和c的时候可能会将a,c较小的贪心放前面,但是我们并不知道b,d是否更小来使得情况更优,所以我们考虑逆向的拓扑排序,我们先来放b,d这样就不会构成矛盾了
代码:
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 205;
int n,m,cnt;
int deg[maxn];
int ans[maxn];
vector<int> G[maxn];
void topsort() {
int t = n;
priority_queue<int> Q;
while(!Q.empty()) Q.pop();
for(int i = 1;i <= n;i++) if(!deg[i]) Q.push(i);
while(!Q.empty()) {
int u = Q.top();Q.pop();
ans[u] = t--;
for(int i = 0;i < G[u].size();i++) {
int v = G[u][i];
deg[v]--;
if(!deg[v]) Q.push(v);
}
}
if(!t) {
for(int i = 1;i <= n;i++) printf("%d ",ans[i]);
printf("
");
}
else printf("-1
");
}
bool check(int u,int v) {
for(int i = 0;i < G[u].size();i++) {
int t = G[u][i];
if(t == v) return false;
}
return true;
}
void init() {
memset(ans,0,sizeof(ans));
memset(deg,0,sizeof(deg));
for(int i = 1;i<=n;i++) G[i].clear();
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
init();
int u,v;
for(int i = 0;i < m;i++) {
scanf("%d%d",&u,&v);
if(check(v,u)) {
G[v].push_back(u);
deg[u]++;
}
}
topsort();
}
return 0;
}