Marriage Match IIHDU - 3081
题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少轮?
首先要想知道每个女孩子能够和哪些男孩子交朋友,就得通过并查集来处理了,每个女孩子可以交朋友的男孩子,和她是朋友的女孩子同样可以交。
然后就是怎么知道能玩几轮。有两个方法。第一个就是最大流。
具体思路就是二分答案,每个女孩子都可以和能和他交朋友的男孩子建一条流量为1的边,就代表可以和他交一次朋友,然后源点与每个女孩子连一条流量为当前二分的这个答案的边,汇点也与每个男孩子连一条流量为当前二分的这个答案的流,这样的话能每个女孩子能够满流的话就是能够玩这么多轮,当前答案是符合的。

1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 using namespace std; 5 const int N=218,M=52118,inf=1000000007; 6 struct Side{ 7 int v,ne,w; 8 }S[M]; 9 int n,sn,sb,se,head[N],dep[N],cur[N],fa[N],ok[N][N]; 10 void init() 11 { 12 sn=0; 13 sb=0,se=2*n+1; 14 for(int i=sb;i<=se;i++) 15 head[i]=-1; 16 } 17 void add(int u,int v,int w) 18 { 19 S[sn].w=w; 20 S[sn].v=v; 21 S[sn].ne=head[u]; 22 head[u]=sn++; 23 } 24 void addE(int u,int v,int w) 25 { 26 add(u,v,w); 27 add(v,u,0); 28 } 29 int gui(int x){ 30 return fa[x]==x ? x : fa[x]=gui(fa[x]); 31 } 32 void bing(int x,int y) 33 { 34 int gx=gui(x),gy=gui(y); 35 if(gx!=gy) 36 fa[gx]=gy; 37 } 38 void bulidE(int limit) 39 { 40 init(); 41 for(int i=1;i<=n;i++) 42 addE(sb,i,limit); 43 for(int i=1;i<=n;i++) 44 addE(n+i,se,limit); 45 for(int i=1;i<=n;i++) 46 for(int j=1;j<=n;j++) 47 if(ok[i][j]) 48 addE(i,n+j,1); 49 } 50 bool bfs() 51 { 52 for(int i=sb;i<=se;i++) 53 dep[i]=0; 54 dep[sb]=1; 55 queue<int> q; 56 q.push(sb); 57 int u,v; 58 while(!q.empty()){ 59 u=q.front(); 60 q.pop(); 61 for(int i=head[u];~i;i=S[i].ne){ 62 v=S[i].v; 63 if(S[i].w>0&&!dep[v]){ 64 dep[v]=dep[u]+1; 65 if(v==se) 66 return true; 67 q.push(v); 68 } 69 } 70 } 71 return false; 72 } 73 int dfs(int u,int minf) 74 { 75 if(u==se||!minf) 76 return minf; 77 int v,flow; 78 for(int &i=cur[u];~i;i=S[i].ne){ 79 v=S[i].v; 80 if(S[i].w>0&&dep[v]==dep[u]+1){ 81 flow=dfs(v,min(minf,S[i].w)); 82 if(flow>0){ 83 S[i].w-=flow; 84 S[i^1].w+=flow; 85 return flow; 86 } 87 } 88 } 89 return 0; 90 } 91 int dinic() 92 { 93 int maxf=0,flow; 94 while(bfs()){ 95 for(int i=sb;i<=se;i++) 96 cur[i]=head[i]; 97 while(flow=dfs(sb,inf)) 98 maxf+=flow; 99 } 100 return maxf; 101 } 102 int solve() 103 { 104 int l=0,r=n,mid,ans=0; 105 while(l<=r){ 106 mid=(l+r)>>1; 107 bulidE(mid); 108 if(dinic()==n*mid) 109 ans=mid,l=mid+1; 110 else 111 r=mid-1; 112 } 113 return ans; 114 } 115 int main() 116 { 117 int t,m,f,a,b; 118 scanf("%d",&t); 119 while(t--) 120 { 121 scanf("%d%d%d",&n,&m,&f); 122 for(int i=1;i<=n;i++){ 123 fa[i]=i; 124 for(int j=1;j<=n;j++) 125 ok[i][j]=0; 126 } 127 while(m--){ 128 scanf("%d%d",&a,&b); 129 ok[a][b]=1; 130 } 131 while(f--){ 132 scanf("%d%d",&a,&b); 133 bing(a,b); 134 } 135 for(int i=1;i<=n;i++) 136 for(int j=1;j<=n;j++) 137 for(int k=1;k<=n;k++) 138 if(gui(i)==gui(j)&&ok[i][k]) 139 ok[j][k]=1; 140 printf("%d ",solve()); 141 } 142 return 0; 143 }
第二种就是二分匹配。我们每次跑一遍匈牙利为每个女孩子匹配一个男孩子,然后再把他们的关系去掉继续匹配 ,最多能匹配多少轮,就是能玩多少轮。

1 #include<cstdio> 2 const int N=118; 3 int n,fa[N],ok[N][N],vis[N],pp[N]; 4 int gui(int x){ 5 return fa[x]==x ? x : fa[x]=gui(fa[x]); 6 } 7 void bing(int x,int y) 8 { 9 int gx=gui(x),gy=gui(y); 10 if(gx!=gy) 11 fa[gx]=gy; 12 } 13 int match(int u) 14 { 15 for(int i=1;i<=n;i++){ 16 if(!vis[i]&&ok[u][i]){ 17 vis[i]=1; 18 if(!pp[i]||match(pp[i])){ 19 pp[i]=u; 20 return 1; 21 } 22 } 23 } 24 return 0; 25 } 26 int solve() 27 { 28 int ans=0,mm; 29 while(1){ 30 mm=0; 31 for(int i=1;i<=n;i++){ 32 for(int j=1;j<=n;j++) 33 vis[j]=0; 34 mm+=match(i); 35 } 36 if(mm==n) 37 ans++; 38 else 39 break; 40 for(int i=1;i<=n;i++){ 41 ok[pp[i]][i]=0; 42 pp[i]=0; 43 } 44 } 45 return ans; 46 } 47 int main() 48 { 49 int t,m,f,a,b; 50 scanf("%d",&t); 51 while(t--) 52 { 53 scanf("%d%d%d",&n,&m,&f); 54 for(int i=1;i<=n;i++){ 55 fa[i]=i; 56 pp[i]=0; 57 for(int j=1;j<=n;j++) 58 ok[i][j]=0; 59 } 60 while(m--){ 61 scanf("%d%d",&a,&b); 62 ok[a][b]=1; 63 } 64 while(f--){ 65 scanf("%d%d",&a,&b); 66 bing(a,b); 67 } 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=n;j++) 70 for(int k=1;k<=n;k++) 71 if(gui(i)==gui(j)&&ok[i][k]) 72 ok[j][k]=1; 73 printf("%d ",solve()); 74 } 75 return 0; 76 }