HDU 3081 Marriage Match II 最大流OR二分匹配

 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\n",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\n",solve());
74     }
75     return 0;
76 }
二分匹配

 

posted @ 2019-07-19 16:40  新之守护者  阅读(164)  评论(0编辑  收藏  举报