【纪中集训2019.3.23】Deadline
题意
描述
一个二分图\((A,B)\),每个点额外有一个颜色0或者1;
匹配时,只能相同颜色的点匹配;
给出\(A\)中的颜色,问如何分配\(B\)种的颜色使得\((A,B)\)的最大匹配最小;
范围
$1 \le n , m \le 2000 \ , \ 1 \le k \le 5000 $
题解
-
将\(A\)中的点按照标号划分为\(v_0和v_1\);
-
将B中的点拆成\(u_0\)和\(u_1\),\(u_0\)向\(u_1\)连流量为\(1\)的边;
-
\(S\)向\(v_0\)连流量为1的边,\(v_1\)向\(T\)连流量为\(1\)的边;
-
\(v_0\)向原图中相连的\(u_0\)连\(inf\)边,\(u_1\)向\(v_1\)连\(inf\)边;
-
简单说明:
-
可以转化为一种标号使得最小点覆盖最小;
-
\(<S,v_0> \ , \ <u_0,u_1> \ , \ <v_1,T>\) 被割分别代表\(v_0,u,v_1\)被选入覆盖集;
-
只需要说明割和合法方案等价:
-
由于不存在一条从\(S\)到\(T\)的残量路径,所以要么\(u\)被割了,要么\(u\)两边相连的点至少一边被割了;
-
这和合法方案的条件是等价的;
-
所以\(ans\)=最小割;
-
考试的时候因为当初做网络流的时候没有理解深刻并且有太久没有做了,所以没有做出来;
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int N=10010; char gc(){ static char*p1,*p2,s[1000000]; if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); return(p1==p2)?EOF:*p1++; } int rd(){ int x=0;char c=gc(); while(c<'0'||c>'9')c=gc(); while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); return x; } int n,m,k,o,hd[N],p[N],S,T,d[N],vis[N],cur[N]; struct Edge{int v,nt,f;}E[N<<1]; void adde(int u,int v,int f){ E[o]=(Edge){v,hd[u],f};hd[u]=o++; E[o]=(Edge){u,hd[v],0};hd[v]=o++; } bool bfs(){ static queue<int>q; for(int i=S;i<=T;++i)d[i]=vis[i]=0; while(!q.empty())q.pop(); d[S]=vis[S]=1;q.push(S); while(!q.empty()){ int u=q.front();q.pop(); for(int i=hd[u];~i;i=E[i].nt)if(E[i].f){ int v=E[i].v; if(vis[v])continue; d[v]=d[u]+1; q.push(v); vis[v]=1; if(v==T)return true; } } return false; } int dfs(int u,int F){ if(u==T||!F)return F; int flow=0,f; for(int i=cur[u];~i;i=E[i].nt){ int v=E[cur[u]=i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].f,F)))){ flow+=f;F-=f; E[i].f-=f;E[i^1].f+=f; if(!F)break; } } return flow; } int dinic(){ int flow=0; while(bfs()){ for(int i=S;i<=T;++i)cur[i]=hd[i]; flow+=dfs(S,inf); } return flow; } int main(){ freopen("deadline.in","r",stdin); freopen("deadline.out","w",stdout); memset(hd,-1,sizeof(hd)); n=rd();m=rd();k=rd();S=0;T=n+m*2+1; for(int i=1;i<=n;++i)if(p[i]=rd())adde(S,2*m+i,1);else adde(2*m+i,T,1); for(int i=1;i<=m;++i)adde(i*2-1,i*2,1); for(int i=1;i<=k;++i){ int u=rd(),v=rd(); if(p[u])adde(m*2+u,v*2-1,inf); else adde(v*2,m*2+u,inf); } int ans=dinic(); cout<<ans<<endl; return 0; }