虽然一次秒过六级,但还是觉得这种冗长的题目非常蛋疼~

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 }