标签:
A.
B.
C.
题意:给出(i, j)之类的约束表示要j必须先i,问1尽量靠前、2尽量靠前、3尽量靠前以此类推的最优方案,或输出无解。
#include <bits/stdc++.h> using namespace std; const int N=100005; int cnt, ihead[N], in[N], ans[N], tot, n, m; struct E { int next, to; }e[N]; void add(int x, int y) { e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt; } priority_queue<int> q; int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); tot=0; for(int i=0; i<m; ++i) { int x, y; scanf("%d%d", &x, &y); add(y, x); in[x]++; } while(q.size()) q.pop(); for(int i=1; i<=n; ++i) if(in[i]==0) q.push(i); while(q.size()) { int x=q.top(); q.pop(); ans[++tot]=x; for(int i=ihead[x]; i; i=e[i].next) if(--in[e[i].to]==0) q.push(e[i].to); } if(tot!=n) puts("Impossible!"); else { for(int i=tot; i>=1; --i) printf("%d ", ans[i]); puts(""); } memset(ihead, 0, sizeof(int)*(n+1)); memset(in, 0, sizeof(int)*(n+1)); cnt=0; } return 0; }
乱搞才5分啊QAQ我竟然忘记我这题做过,我是有多弱TAT(就算做过我也不会证明= =)
于是果断orz zyf神犇
http://zyfzyf.is-programmer.com/posts/89618.html
这里有两道看起来十分相似的题目:
我们对比一下这两道题目:
查错要求:求一个拓扑序,使得字典序尽可能小。
拓扑编号要求:求一个拓扑序,使得1尽量往前,在此情况下,2尽量往前。一次类推。
需要注意,这两个要求肯定是不同的。
例如在拓扑编号中 4 1 2 3 5是比 3 1 4 2 5 (当然不一定合法)优的,因为2的位置比较靠前。
我们分别来叙述这两个问题的解法:
查错 只要按正常的拓扑排序,只不过把queue改成priority_queue即可。正确性显然。
拓扑编号 我们反向拓扑排序,每次取出出度为0的最大的节点,标号,然后用它去更新其他点的出度。
这个算法的证明我是在这里看到的:算法证明
这里再口胡一下:
不妨认为我们这样得到的不是最优解,那么令这样得到的序列为a,然后最优解是b。
我们从后往前开始找到第一位两个序列不同的一位设为k,那么a[k]!=b[k],且a[k]>b[k]。(由a的构造方式可知)(先假设这个k存在,再证出矛盾)
再设a[k]出现的b的p位置,即b[p]=a[k]。再设b[p] b[p+1]……b[k]这个子序列为C。
那么b[p]一定不是C中的最小元素,因为有b[k]<b[p]=a[k]。
然后不妨设b[q]为C的最小元素。然后我们把b[p]移到b[k]的位置,得到序列bb。
如果bb合法的话,那么我们就得到了一个比b优的解,这与b是最优解矛盾。
(因为b[q]的位置前移了一位,我们要求编号小的尽可能靠前)
但bb显然是合法的。因为在a序列中k以及后面的是合法的,那么b后面也这么做一定也是合法的。
所以一定不存在某个k,使得a[k]!=b[k]。也就是说a=b。
所以算法正确性得证。(证法和链接里有点不一样,但我认为也是正确的)
标签:
原文地址:http://www.cnblogs.com/iwtwiioi/p/4458148.html