[数据结构] 拓扑排序
模板
int c[maxn];
int topo[maxn];
bool dfs(int u){
c[u] = -1; //正在访问标志
for(int v = 0; v < n; v++){
if(c[v] <-1) return false; //存在有向环
else if(!c[v] && !dfs(v)) return false;
}
c[u] = 1; //已访问标志,并且还递归访问过其所有子孙
return true;
}
bool toposort(){
memset(c, 0, sizeof(c));
for(int u = 0; u < n; u++) if(!c[u])
if(!dfs(u)) return false;
return true;
}
应用
Self-Assembly [UVa 1572]
题目描述
Automatic Chemical Manufacturing is experimenting with a process called self-assembly. In this process, molecules with natural affinity for each other are mixed together in a solution and allowed to spontaneously assemble themselves into larger structures. But there is one problem: sometimes molecules assemble themselves into a structure of unbounded size, which gums up the machinery.You must write a program to decide whether a given collection of molecules can be assembled into a structure of unbounded size. You should make two simplifying assumptions: 1) the problem is restricted to two dimensions, and 2) each molecule in the collection is represented as a square. The four edges of the square represent the surfaces on which the molecule can connect to other compatible molecules.In each test case, you will be given a set of molecule descriptions. Each type of molecule is described by four two-character connector labels that indicate how its edges can connect to the edges of other molecules. There are two types of connector labels:
An uppercase letter (A, …, Z) followed by + or -. Two edges are compatible if their labels have the same letter but different signs. For example, A+ is compatible with A- but is not compatible with A+ or B-.
Two zero digits 00. An edge with this label is not compatible with any edge (not even with another edge labeled 00).
Assume there is an unlimited supply of molecules of each type, which may be rotated and reected.As the molecules assemble themselves into larger structures, the edges of two molecules may be adjacent to each other only if they are compatible. It is permitted for an edge, regardless of its connector label,to be connected to nothing (no adjacent molecule on that edge).Figure A.1 shows an example of three molecule types and a structure of bounded size that can be assembled from them (other bounded structures are also possible with this set of molecules).
AC代码
#include <cstdio>
#include <cstring>
const int maxn = 52;
int c[maxn];
bool g[maxn][maxn];
int id(char a1, char a2){
return (a1-'A')*2+(a2 == '+'?0:1);
}
void connect(char a1, char a2, char b1, char b2){
if(a1 == '0' || b1 == '0') return;
int u = id(a1, a2)^1, v = id(b1, b2);
g[u][v] = true;
}
bool toposort(int u){
c[u] = -1;
for(int v = 0; v < maxn; ++v)
if(g[u][v]){
if(c[v] < 0) return true;
else if(!c[v] && toposort(v)) return true;
}
c[u] = 1;
return false;
}
bool cycle(){
memset(c, 0, sizeof(c));
for(int i = 0; i < maxn; i++)
if(!c[i]) if(toposort(i)) return true;
return false;
}
int main(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int n;
while(~scanf("%d", &n) && n){
memset(g, false, sizeof(g));
while(n--){
char s[10];
scanf("%s", s);
for(int i = 0; i < 4; i++)
for(int j = 0; j<4; j++)
if(i != j) connect(s[i*2], s[i*2+1], s[j*2], s[j*2+1]);
}
printf("%s\n", cycle()?"unbounded": "bounded");
}
}
分析
本题有两个难点:
- 通过分析将题目求解与拓扑排序联系
- 拓扑排序的具体实现
可从题目分析出,若可以拼成一个无限大的图,那么在模拟过程中必然出现正在拼接的某个正方形与第一块正方形相同。若无法拼接下去则不能拼成一个无限大的图。
若以这种模拟的想法做,则有两个很严重的问题:1.题目要求每条边都“悬空”,在模拟过程中很难保证“悬空”。2.若某种情况不能拼成无限大的图,那在模拟过程中时间开销很大。
在借鉴别人思路后,发现题目有这样一个条件可以旋转和翻转。这个条件可以使图像只向右和下伸展。不能拼成无限大结构的判定条件也变为:某块不能再向下和向右拼接。
在进一步分析,拼接可以看成上一块的某个字母(如A+)旭下一块的其余字母(除去对应字母A-)的有向连接。这样被转化为一个拓扑排序的问题。