虽然一次秒过六级,但还是觉得这种冗长的题目非常蛋疼~
3进制位压缩以进行判断是否有边,接着就是一次最大流,判断最后经过了哪些边只用考虑拆点后右边的点发出去的通往左边的点的那些边里初始流量减去现在流量是否等于0即可。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=200,M=20000; 6 const int inff=10000000; 7 int head[N],nc; 8 struct edge 9 { 10 int x,y,next; 11 int cap; 12 } edge[M*3]; 13 void add(int x,int y,int cap) 14 { 15 edge[nc].x=x; 16 edge[nc].y=y; 17 edge[nc].cap=cap; 18 edge[nc].next=head[x]; 19 head[x]=nc++; 20 edge[nc].x=y; 21 edge[nc].y=x; 22 edge[nc].cap=0; 23 edge[nc].next=head[y]; 24 head[y]=nc++; 25 } 26 int num[N],h[N],S,T,n; 27 int findpath(int x,int flow) 28 { 29 if(x==T) 30 return flow; 31 int res=flow,pos=n-1; 32 for(int i=head[x]; i!=-1; i=edge[i].next) 33 { 34 int y=edge[i].y; 35 if(h[x]==h[y]+1&&edge[i].cap>0) 36 { 37 int tp=findpath(y,min(edge[i].cap,res)); 38 res-=tp; 39 edge[i].cap-=tp; 40 edge[i^1].cap+=tp; 41 if(!res||h[S]==n) 42 return flow-res; 43 } 44 if(edge[i].cap>0&&h[y]<pos) 45 pos=h[y]; 46 } 47 if(res==flow) 48 { 49 num[h[x]]--; 50 if(num[h[x]]==0) 51 { 52 h[S]=n; 53 return flow-res; 54 } 55 h[x]=pos+1; 56 num[h[x]]++; 57 } 58 return flow-res; 59 } 60 int Sap() 61 { 62 memset(h,0,sizeof(h)); 63 memset(num,0,sizeof(num)); 64 int ans=0; 65 num[0]=n; 66 while(h[S]!=n) 67 ans+=findpath(S,inff); 68 return ans; 69 } 70 struct data 71 { 72 int cap,from,to; 73 }po[N]; 74 bool check(int ff,int tt) 75 { 76 while(ff||tt) 77 { 78 int a=ff%3,b=tt%3; 79 if((a==0&&b==1)||(a==1&&b==0)) 80 return false; 81 ff/=3;tt/=3; 82 } 83 return true; 84 } 85 struct out 86 { 87 int a,b,w; 88 }out[N*N]; 89 int main() 90 { 91 int p,m; 92 while(scanf("%d%d",&p,&m)!=EOF) 93 { 94 n=2*m+2; 95 S=0,T=2*m+1; 96 memset(head,-1,sizeof(head)); 97 nc=0; 98 for(int i=1;i<=m;i++) 99 { 100 scanf("%d",&po[i].cap); 101 add(i,i+m,po[i].cap); 102 int sum=0,tp,flag=1; 103 for(int j=0;j<p;j++) 104 { 105 scanf("%d",&tp); 106 if(tp==1) 107 flag=0; 108 sum=sum*3+tp; 109 } 110 po[i].from=sum; 111 if(flag) 112 add(S,i,inff); 113 sum=0; 114 flag=1; 115 for(int j=0;j<p;j++) 116 { 117 scanf("%d",&tp); 118 if(tp==0) 119 flag=0; 120 sum=sum*3+tp; 121 } 122 if(flag) 123 add(i+m,T,inff); 124 po[i].to=sum; 125 for(int j=1;j<i;j++) 126 { 127 if(check(po[i].to,po[j].from)) 128 add(i+m,j,inff); 129 if(check(po[j].to,po[i].from)) 130 add(j+m,i,inff); 131 } 132 } 133 int ans=Sap(),cnt=0; 134 for(int i=1+m;i<T;i++) 135 { 136 for(int j=head[i];j!=-1;j=edge[j].next) 137 { 138 int w=inff-edge[j].cap,b=edge[j].y; 139 if(b!=T&&w!=0&&b!=i-m) 140 { 141 out[cnt].a=i-m;out[cnt].b=b;out[cnt].w=w; 142 cnt++; 143 } 144 } 145 } 146 printf("%d %d\n",ans,cnt); 147 for(int i=0;i<cnt;i++) 148 printf("%d %d %d\n",out[i].a,out[i].b,out[i].w); 149 } 150 return 0; 151 }