BZOJ3355
3355: [Usaco2004 Jan]有序奶牛
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 37 Solved: 19
[Submit][Status][Discuss]
Description
约翰的N(1≤N≤1500)头牛排成一行挤奶时,有确定的顺序.牛被编成连续的号码1..N,他拥有L条关于奶牛顺序的信息,所有的信息都写成“A在B的前面”这样的形式,而且他知道最后一条是多余的.他觉得,有些冗余信息可以由其他信息推出,可以对这些信息进行精减.请帮助约翰删除尽可能多的冗余信息,但要保证能推出原有的顺序.可以保证的是,答案唯一,且最初的信息没有矛盾,如A在B前面,B在A前面.
Input
第1行:两个整数N和L.
第2到L+1行:每行两个整数X和Y(1≤X,y≤N),表示X在Y前.无重复.
Output
第1行:整数U.
第2到U+I行:输出精减后的信息,每行2个数字,按第1列数字排序.
Sample Input
5 6
3 5
4 2
5 2
2 1
3 1
4 1
3 5
4 2
5 2
2 1
3 1
4 1
Sample Output
4
2 1
3 5
4 2
5 2
2 1
3 5
4 2
5 2
HINT
3在1前,4在1前可推.输出的每一行,不能被其他推出.
分析:对于一条边x->y,若去掉之后x不能到达y,那么它是必需的。我们首先需要求出拓扑序列,然后我们按照拓扑序列反向加边,这样的目的就是为了在已知顺序的情况下维护哪些边可以互相到达,然后用一个bieset去判断一下哪些边是必须的。感谢claris和付大神对我的帮助
1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "bitset" 5 #include "algorithm" 6 using namespace std; 7 const int maxn=1500+10; 8 const int maxm=15000+10; 9 int n,m,ed,ed2; 10 int ind[maxn]; //入度 11 int adj[maxm]; //栈顶边对应的顶点 12 int next1[maxm]; //上一条边的编号 13 int tail[maxm]; //栈顶边的编号 14 int vis[maxn]; //存储拓扑排序序列 15 bitset<maxn>f[maxn]; 16 void add(int x,int y){ 17 ind[y]++; 18 adj[++ed]=y; 19 next1[ed]=tail[x]; 20 tail[x]=ed; 21 } 22 int adj2[maxm]; 23 int next2[maxm]; 24 int tail2[maxm]; 25 void add2(int x,int y){ 26 adj2[++ed2]=y; 27 next2[ed2]=tail2[x]; 28 tail2[x]=ed2; 29 } 30 typedef pair<int,int> P; 31 P p[maxm]; 32 int main() 33 { 34 //freopen("a.txt", "r", stdin); 35 //freopen("b.txt", "w", stdout); 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=n;i++) f[i][i]=1; 38 ed=0; 39 while(m--){ //数组式邻接表建图 40 int x,y; 41 scanf("%d%d",&x,&y); 42 add(x,y); 43 } 44 45 //构造拓扑排序序列 46 int cnt=0; 47 for(int i=1;i<=n;i++) 48 if(!(ind[i])) 49 vis[++cnt]=i; 50 51 int h=1; 52 ed2=0; 53 while(h<=cnt){ 54 int a; 55 for(int i=tail[a=vis[h++]];i;add2(adj[i],a),i=next1[i]) 56 if(!(--ind[adj[i]])) 57 vis[++cnt]=adj[i]; 58 } 59 60 int ans=0; 61 for(int i=1;i<=n;i++){ 62 int a; 63 for(int j=tail2[a=vis[i]];j;f[a]|=f[adj2[j]],j=next2[j]) 64 if(!f[a][adj2[j]]) 65 p[++ans]=P(adj2[j],a); 66 } 67 sort(p+1,p+1+ans); 68 printf("%d\n",ans); 69 for(int i=1;i<=ans;i++) 70 printf("%d %d\n",p[i].first,p[i].second); 71 return 0; 72 }