标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3558 Accepted Submission(s): 1158
#include<iostream> #include<cstdio> #include<cstring> #include <algorithm> #include <math.h> #include <queue> using namespace std; const int N = 205; const int INF = 999999999; struct Edge{ int v,w,next; }edge[N*N]; int head[N]; int level[N]; int tot,max_increase; void init() { memset(head,-1,sizeof(head)); tot=0; } void addEdge(int u,int v,int w,int &k) { edge[k].v = v,edge[k].w=w,edge[k].next=head[u],head[u]=k++; edge[k].v = u,edge[k].w=0,edge[k].next=head[v],head[v]=k++; } int BFS(int src,int des) { queue<int>q; memset(level,0,sizeof(level)); level[src]=1; q.push(src); while(!q.empty()) { int u = q.front(); q.pop(); if(u==des) return 1; for(int k = head[u]; k!=-1; k=edge[k].next) { int v = edge[k].v; int w = edge[k].w; if(level[v]==0&&w!=0) { level[v]=level[u]+1; q.push(v); } } } return -1; } int dfs(int u,int des,int increaseRoad){ if(u==des||increaseRoad==0) { return increaseRoad; } int ret=0; for(int k=head[u];k!=-1;k=edge[k].next){ int v = edge[k].v,w=edge[k].w; if(level[v]==level[u]+1&&w!=0){ int MIN = min(increaseRoad-ret,w); w = dfs(v,des,MIN); if(w > 0) { edge[k].w -=w; edge[k^1].w+=w; ret+=w; if(ret==increaseRoad){ return ret; } } else level[v] = -1; if(increaseRoad==0) break; } } if(ret==0) level[u]=-1; return ret; } int Dinic(int src,int des) { int ans = 0; while(BFS(src,des)!=-1) ans+=dfs(src,des,INF); return ans; } bool vis[N][N],vis1[N][N]; int n,m,f; int father[N]; int _find(int u){ if(father[u]!=u){ father[u] = _find(father[u]); } return father[u]; } void build(int c){ init(); for(int i=1;i<=n;i++){ for(int j=1+n;j<=n+n;j++){ vis[i][j] = vis1[i][j]; } } int src = 0,des = 2*n+1; for(int i=1;i<=n;i++){ addEdge(src,i,c,tot); addEdge(i+n,des,c,tot); } for(int i=1;i<=n;i++){ for(int j=1+n;j<=n+n;j++){ if(vis[i][j]) addEdge(i,j,1,tot); } } /**本题难点*/ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(_find(i)==_find(j)){ for(int k=1+n;k<=2*n;k++){ if(vis[i][k]&&!vis[j][k]){ addEdge(j,k,1,tot); vis[j][k] = 1; } } } } } } int main() { int tcase; scanf("%d",&tcase); while(tcase--){ scanf("%d%d%d",&n,&m,&f); for(int i=1;i<=n;i++) father[i] = i; memset(vis,false,sizeof(vis)); memset(vis1,false,sizeof(vis1)); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); v+=n; vis[u][v] = vis1[u][v] = true; } for(int i=1;i<=f;i++){ int u,v; scanf("%d%d",&u,&v); int a = _find(u),b = _find(v); father[a] = b; } int l =0,r = n,ans = 0; while(l<=r){ int mid = (l+r)>>1; build(mid); if(Dinic(0,2*n+1)==n*mid){ ans = mid; l = mid+1; }else r = mid-1; } printf("%d\n",ans); } return 0; }
题解二:二分图,建好边之后每次匹配完如果最大匹配还是n的话就删完匹配边继续进行下一次匹配,知道最大匹配<n.难点还是在于建图.
#include<iostream> #include<cstdio> #include<cstring> #include <algorithm> #include <math.h> #include <queue> using namespace std; const int N = 205; int graph[N][N]; int linker[N]; bool vis[N]; int father[N]; int n,m,f; int _find(int u){ if(father[u]!=u){ father[u] = _find(father[u]); } return father[u]; } bool dfs(int u){ for(int v=1;v<=n;v++){ if(graph[u][v]&&!vis[v]){ vis[v] = true; if(linker[v]==-1||dfs(linker[v])){ linker[v] = u; return true; } } } return false; } int main() { int tcase; scanf("%d",&tcase); while(tcase--){ scanf("%d%d%d",&n,&m,&f); for(int i=1;i<=n;i++) father[i] = i; memset(graph,0,sizeof(graph)); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); graph[u][v] = 1; } for(int i=1;i<=f;i++){ int u,v; scanf("%d%d",&u,&v); int a = _find(u),b = _find(v); father[a] = b; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(_find(i)==_find(j)){ for(int k=1;k<=n;k++){ if(graph[i][k]) graph[j][k] = 1; } } } } int ans = 0; while(1){ int res = 0; memset(linker,-1,sizeof(linker)); for(int i=1;i<=n;i++){ memset(vis,false,sizeof(vis)); if(dfs(i)) res++; } if(res<n) break; ans++; for(int i=1;i<=n;i++){ if(linker[i]!=-1){ graph[linker[i]][i] = 0; } } } printf("%d\n",ans); } return 0; }
总结:能用二分图就别用网络流。
标签:
原文地址:http://www.cnblogs.com/liyinggang/p/5723428.html