题解 拓扑排序 POJ 3687
题意:n个重量为1~n的球,给定一些编号间的重量比较关系,现在给每个球编号,在符合条件的前提下使得编号小的球重量小。(先保证1号球最轻,其次2号……)
分析:拓扑排序,注意根据题的要求,要先保证1号球最轻,如果我们由轻的向重的连边,然后我们依次有小到大每次把重量分给一个入度为0的点,那么在拓扑时我们面对多个入度为0的点,我们不知道该把最轻的分给谁才能以最快的速度找到1号(使1号入度为0),并把当前最轻的分给1号。所以我们要由重的向轻的连边,然后从大到小每次把一个重量分给一个入度为0的点。这样我们就不用急于探求最小号。我们只需要一直给最大号附最大值,尽量不给小号赋值,这样自然而然就会把轻的重量留给小号。注意重边。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define maxn 205 bool g[maxn][maxn]; bool vis[maxn]; int in[maxn]; int ans[maxn]; int n, m; void input() { scanf("%d%d", &n, &m); memset(g, 0, sizeof(g)); memset(in, 0, sizeof(in)); for (int i =0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); a--; b--; if (!g[b][a]) in[a]++; g[b][a] =true; } } void work() { memset(vis, 0, sizeof(vis)); for (int i = n; i >0; i--) { int q =-1; for (int j = n -1; j >=0; j--) if (!vis[j] &&in[j] ==0) { q = j; break; } if (q ==-1) { printf("-1\n"); return; } vis[q] =true; ans[q] = i; for (int j =0; j < n; j++) if (g[q][j]) in[j]--; } printf("%d", ans[0]); for (int i =1; i < n; i++) printf(" %d", ans[i]); putchar('\n'); } int main() { //freopen("t.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { input(); work(); } return 0; }注:摘自于网上,至今未能理解。。。