ACM/ICPC 之 拓扑排序-反向(POJ3687)
难点依旧是题意。。。。需要反向构图+去重+看题
POJ3687-Labeling Balls
题意:1-N编号的球,输出满足给定约束的按原编号排列的重量序列,如果有多组答案,则输出编号最小的Ball重量最轻,若依旧多组则输出编号次小的Ball重量最轻的方案。
题解:在看懂题意后,再开始做会省很多时间。。。曲解题意还真是人类的本能啊。
为了完成单向关系排序,需要用到拓扑排序;
为了符合编号最小的重量最轻...的题意,需要用到反向拓扑排序;
输入可能会有重复的关系,因此需要判重;
输出需要按原编号输出其重量,因此需要在每个编号上标记其重量。
1 //给球编号 2 //1-N编号的球,输出满足给定约束的按原编号排列的重量序列,如果有多组答案,则输出编号越小重量越轻的方案 3 //反向拓扑+去重+看题...(题意最后需要将Ball的重量按原编号输出) 4 //迭代器判重:Time:125Ms Memory:524K 5 //数组判重: Time:63Ms Memory:564K 6 #include<iostream> 7 #include<cstring> 8 #include<cstdio> 9 #include<vector> 10 using namespace std; 11 12 #define MAX 205 13 14 struct Number { 15 vector<int> light; 16 int in; //in_degree 17 int weight; //该编号球的重量 18 }num[MAX]; 19 20 int n, m; 21 bool v[MAX][MAX]; 22 23 bool TopSort() 24 { 25 for (int t = n; t > 0; t--) //最重到最轻 26 { 27 int cur = n + 1; 28 while (--cur && num[cur].in); //将最大的label先取出放在最后 29 if (cur == 0) return false; //有环 30 31 num[cur].weight = t; //记录重量 32 num[cur].in--; 33 for (unsigned j = 0; j < num[cur].light.size(); j++) 34 num[num[cur].light[j]].in--; 35 } 36 return true; 37 } 38 39 int main() 40 { 41 int T; 42 scanf("%d", &T); 43 while (T--) 44 { 45 memset(num, 0, sizeof(num)); 46 memset(v, false, sizeof(v)); 47 scanf("%d%d", &n, &m); 48 for (int i = 0; i < m; i++) 49 { 50 int light, heavy; 51 scanf("%d%d", &light, &heavy); 52 //反向构图 53 //迭代器判重 54 //vector<int> lg = num[heavy].light; 55 //if (find(lg.begin(), lg.end(), light) != lg.end()) continue; 56 //数组判重 57 if (v[heavy][light]) continue; 58 v[heavy][light] = true; 59 num[heavy].light.push_back(light); 60 num[light].in++; 61 } 62 63 if (TopSort()) 64 { 65 for (int i = 1; i < n; i++) 66 printf("%d ", num[i].weight); 67 printf("%d\n", num[n].weight); 68 } 69 else printf("-1\n"); 70 71 } 72 73 return 0; 74 }
他坐在湖边,望向天空,她坐在对岸,盯着湖面