HDU-3081 Marriage Match II
阿新 • • 發佈:2018-10-31
挺有意思的一題,關鍵點在於要先假設可以有K輪匹配,再用最大流跑看是否可行
我看的題解:https://blog.csdn.net/u013480600/article/details/38961991
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=220+10; const int M=3e4+10; const int INF=0x7f7f7f7f; struct Edge { int to,nxt,cap,flow; }edge[M]; int tot,first[N]; void addedge(int u,int v,int w,int rw=0) { edge[tot].to=v;edge[tot].cap=w;edge[tot].flow=0; edge[tot].nxt=first[u];first[u]=tot++; edge[tot].to=u;edge[tot].cap=rw;edge[tot].flow=0; edge[tot].nxt=first[v];first[v]=tot++; } void init() { tot=0; memset(first,-1,sizeof(first)); } int gap[N],dep[N],cur[N]; int Q[N],S[N]; void bfs(int s) { memset(gap,0,sizeof(gap)); memset(dep,-1,sizeof(dep)); int q0=0,q1=0; Q[q1++]=s; dep[s]=0; gap[0]=1; while(q0<q1) { int u=Q[q0++]; for(int i=first[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(dep[v]!=-1) continue; dep[v]=dep[u]+1; gap[dep[v]]++; Q[q1++]=v; } } } int sap(int s,int t,int n) { int ans=0; bfs(t); memcpy(cur,first,sizeof(first)); int top=0; int u=s; while(dep[s]<n) { if(u==t) { int Min=INF; int inser; for(int i=0;i<top;i++) if(Min>edge[S[i]].cap-edge[S[i]].flow) { Min=edge[S[i]].cap-edge[S[i]].flow; inser=i; } for(int i=0;i<top;i++) { edge[S[i]].flow+=Min; edge[S[i]^1].flow-=Min; } ans+=Min; top=inser; u=edge[S[top]^1].to; } bool flag=false; int v; for(int i=cur[u];i!=-1;i=edge[i].nxt) { v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) { flag=true; cur[u]=S[top++]=i; break; } } if(flag) { u=v; continue; } gap[dep[u]]--; if(!gap[dep[u]]) return ans; int Min=n; for(int i=first[u];i!=-1;i=edge[i].nxt) if(edge[i].cap-edge[i].flow&&Min>dep[edge[i].to]) { Min=dep[edge[i].to]; cur[u]=i; } dep[u]=Min+1; gap[dep[u]]++; if(u!=s) u=edge[S[--top]^1].to; } return ans; } int g[N][N]; int main() { int T; int n,m,f; scanf("%d",&T); while(T--) { init(); memset(g,0,sizeof(g)); scanf("%d%d%d",&n,&m,&f); int s=0,t=2*n+1; for(int i=1;i<=n;i++) addedge(n+i,t,2); for(int i=1;i<=n;i++) addedge(s,i,2); int cnt=tot; int u,v; for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); g[u][v+n]=1; } for(int i=0;i<f;i++) { scanf("%d%d",&u,&v); g[u][v]=g[v][u]=1; } for(int i=1;i<=2*n;i++) for(int j=1;j<=2*n;j++) { if(i==j) continue; for(int k=1;k<=2*n;k++) if(g[i][k]&&g[k][j]) g[i][j]=1; } for(int i=1;i<=n;i++) for(int j=n+1;j<=2*n;j++) if(g[i][j]) addedge(i,j,1); int ans=0,l=1,r=n; while(l<r) { int k=(l+r)>>1; for(int i=0;i<cnt;i++) if(edge[i].cap) edge[i].cap=k; for(int i=0;i<tot;i++) edge[i].flow=0; int num=sap(s,t,t+1); if(num==k*n) { ans=k; l=k+1; } else { r=k; } } int k=(l+r)>>1; for(int i=0;i<cnt;i++) if(edge[i].cap) edge[i].cap=k; for(int i=0;i<tot;i++) edge[i].flow=0; int num=sap(s,t,t+1); if(num==k*n) ans=k; printf("%d\n",ans); } return 0; }