題意
給出一個二分圖,左邊為A集合,右邊為B集合,要求把A集合中每一個點染為黑白兩色中的一種,B集合中的顏色已定。染色後對於原本相鄰且顏色相同的點,建立新的二分圖,即得到了兩個新的二分圖,它們是獨立的。求出這兩個新的二分圖的最大匹配數的和的最小值。數均小於等於5000。
思考
這是簡化題意。由於暴力很難寫,考慮網路流。將B集合中的每一個點根據其顏色分為一類和二類點。對於A集合中的每一個點,拆成兩個點,兩點連1的單向邊,將所有相鄰的一類點連線左邊,另一類連向右邊,值為1。所有二類點連向匯點,源點連向所有一類點。最小割。
這樣,若割掉了某條邊,代表了將某個點相鄰的所有A集合中的點都染成了相同的顏色,並斷絕了其他點的後路。
程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E5+5; 4 const int inf=INT_MAX; 5 int head[maxn*2],size=1,n,m,a[maxn],dfn[maxn],S,T,x,y,ans,k; 6 struct edge{int to,next,w;}E[maxn*2]; 7 void add(int u,int v,int w) 8 { 9 E[++size].to=v; 10 E[size].next=head[u]; 11 E[size].w=w; 12 head[u]=size; 13 14 E[++size].to=u; 15 E[size].next=head[v]; 16 E[size].w=0; 17 head[v]=size; 18 } 19 bool bfs() 20 { 21 queue<int>Q; 22 for(int i=0;i<=T;++i)dfn[i]=-1; 23 dfn[S]=0; 24 Q.push(S); 25 while(Q.size()) 26 { 27 int u=Q.front(); 28 Q.pop(); 29 for(int i=head[u];i;i=E[i].next) 30 { 31 int v=E[i].to; 32 if(E[i].w==0||dfn[v]!=-1)continue; 33 dfn[v]=dfn[u]+1; 34 Q.push(v); 35 } 36 } 37 return dfn[T]!=-1; 38 } 39 int dinic(int u,int up) 40 { 41 if(u==T)return up; 42 int sum=0; 43 for(int i=head[u];i;i=E[i].next) 44 { 45 int v=E[i].to; 46 if(E[i].w==0||dfn[v]!=dfn[u]+1)continue; 47 int g=dinic(v,min(E[i].w,up-sum)); 48 E[i].w-=g; 49 E[i^1].w+=g; 50 sum+=g; 51 if(g==0)dfn[v]=-1; 52 if(sum==up)break; 53 } 54 return sum; 55 } 56 int main() 57 { 58 // freopen("deadline.in","r",stdin); 59 // freopen("deadline.out","w",stdout); 60 ios::sync_with_stdio(false); 61 cin>>n>>m>>k; 62 for(int i=1;i<=n;++i)cin>>a[i]; 63 for(int i=1;i<=k;++i) 64 { 65 cin>>x>>y; 66 if(a[x])add(x,y+n,inf); 67 else add(y+n+m,x,inf); 68 } 69 S=0; 70 T=n+m*2+1; 71 for(int i=1;i<=m;++i)add(i+n,i+n+m,1); 72 for(int i=1;i<=n;++i) 73 if(a[i])add(S,i,1); 74 else add(i,T,1); 75 while(bfs())ans+=dinic(S,inf); 76 cout<<ans<<endl; 77 return 0; 78 }