题目大意:给定关系啊a,b,表示a必须在b前面。无关系时按升序排列(小数优先满足)。排序后,用1-n为其贴标签,输出1-n号球上的标签。
【解题思路】:关键[ 反向建图 ] 、[ 优先队列(less) ]。
【论证】:拓扑排序显然能保证给定关系。问题在于反向建图。
首先说明以下两点:
反向建图且less优先队列,则pop的元素是【后方无边,且在队列中最大】(迫不得已才被pop)(pop顺序是反向所求队列,该在ans后面的先pop)
那么正向建图,greater优先队列,pop的是【前方无边,且在队列中最小】
(pop顺序是正向所求队列,该在ans前面的先pop)
来讨论一例子 1,2 ,3 需要满足3,1 ;
①正序建图,对于1,只因关系前方的3大,即使1自己很小,也进不去队列,2明明比1大,且和1无关系,2却先进队列在1前面pop。得到序列(2 3 1)
②同理想到反向建图也存在问题
下面讨论反向建图,对于3,只因关系后方1小,即使3大,也进不去队列,2明明比3小,且和3无关系,2却先进队列,在3面前pop()。得到序列(3 1 2)。
对于此例,两组无关数对(2,3与1,2)必有一组无法满足升序,但题干要求优先满足较小的数,所以先满足1在2前因此反向建图正确
(正解序列为 3 1 2;输出为:2 3 1;)。
仔细想想为什么,明明反向图存在问题可反向图是正确的,因为在反向图出现问题的前提,是已经使得一个更小的数(数1)排在比较小的数(数2),因此肯定无法满足比较小的数(数2)排在较大的数(数3)之前。但却满足题干中的下面的话
If several solutions exist, you should output the one with the smallest weight for label 1, then with the smallest weight for label 2, then with the smallest weight for label 3 and so on... If no solution exists, output -1 instead
【也就是说小数优先满足升序】
1 #include "cstring" 2 #include "iostream" 3 #include "cstdio" 4 #include "queue" 5 #include "vector" 6 using namespace std; 7 vector<</span>int> E[203]; 8 bool ins[203]; 9 int k[203][203]; 10 int r[203]; 11 bool p; 12 int ans[203]; 13 int pout[203]; 14 priority_queue<</span>int, vector<</span>int>, less<</span>int> > s; 15 int main() 16 { 17 int n, m, N, I; 18 cin >> N; 19 while (N--) 20 { 21 cin >> n >> m; 22 p = false; 23 memset(ins, false, sizeof(ins)); 24 memset(E, 0, sizeof(E)); 25 memset(r, 0, sizeof(r)); 26 memset(ans, 0, sizeof(ans)); 27 memset(k, 0, sizeof(k)); 28 memset(pout, 0, sizeof(pout)); 29 for (int i = 1; i <= m ; i++) 30 { 31 int a, b; 32 scanf("%d%d", &a, &b); 33 E[b].push_back(a); 34 r[a]++; 35 } 36 for (int i = 1; i <= n; i++) 37 { 38 if (r[i] == 0) 39 { 40 s.push(i); 41 ins[i] = true; 42 } 43 } 44 I = n; 45 while (!s.empty()) 46 { 47 int now = s.top(); 48 ans[I--] = now; 49 s.pop(); 50 for (int i = 0; i < E[now].size(); i++) 51 { 52 if (((--r[E[now][i]]) == 0) && (!ins[E[now][i]])) 53 { 54 s.push(E[now][i]); 55 ins[E[now][i]] = true; 56 } 57 } 58 E[now].clear(); 59 } 60 for (int i = 1; i <= n; i++) 61 { 62 pout[ans[i]] = i; 63 if (ins[i] == false) p = true; 64 } 65 if (n == 0) continue; 66 if (p) 67 { 68 printf("-1\n"); 69 continue; 70 } 71 for (int i = 1; i < n; i++) 72 printf("%d ", pout[i]); 73 printf("%d\n", pout[n]); 74 } 75 }