【HDU3081】Marriage Match II (二分+最大流)

Description
Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends playing together. And it is normal that a fight or a quarrel breaks out, but we will still play together after that, because we are kids. 
Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend. 
Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on. 
Now, here is the question for you, how many rounds can these 2n kids totally play this game? 

Input

There are several test cases. First is a integer T, means the number of test cases. 
Each test case starts with three integer n, m and f in a line (3<=n<=100,0<m<n*n,0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n). 
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other. 
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends. 

Output

For each case, output a number in one line. The maximal number of Marriage Match the children can play.

Sample Input

1 4 5 2 1 1 2 3 3 2 4 2 4 4 1 4 2 3

Sample Output

2
 
 
 
【题意】

  n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她朋友能配对的男生配对。

每次配对,每个女生都要跟不同的男生配对且每个女生都能配到对。问最多能配对几轮。(n<=100)

 

【分析】

  二分答案,因为有单调性。然后直接最大流了。输入那里要用并查集。

  注意不能直接跑最大流哦,(因为你不知道跑完最大流之后ans是啥啊)

 

  哇塞~TLE了一辈子,dinic中几个不起眼的优化也能是可以挽救你于水火之中啊。比如下面的加粗部分:

int find_flow(int x,int flow)
{
  if(x==ed) return flow;
  int now=0;
  for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
  {
    int y=t[i].y;
    if(dis[y]==dis[x]+1)
    {
      int a=find_flow(y,mymin(t[i].f,flow-now));
      t[i].f-=a;
      t[t[i].o].f+=a;
      now+=a;
      if(now==flow) break;
    }
  }
  if(now==0) dis[x]=-1;
  return now;
}

 

 

  我这个傻逼还因为数组开小了TLE了好一阵子。

 

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 210
  9 #define Maxm 10010
 10 #define INF 0xfffffff
 11 
 12 int fa[Maxn],first[Maxn],dis[Maxn];
 13 bool map[Maxn][Maxn];
 14 
 15 struct node
 16 {
 17     int x,y,f,o,next;
 18 };
 19 node t[10*Maxm],tt[10*Maxm];int len;
 20 
 21 int st,ed;
 22 int n,m,k;
 23 
 24 int mymin(int x,int y) {return x<y?x:y;}
 25 
 26 void ins(int x,int y,int f)
 27 {
 28     tt[++len].x=x;tt[len].y=y;tt[len].f=f;
 29     tt[len].next=first[x];first[x]=len;tt[len].o=len+1;
 30     tt[++len].x=y;tt[len].y=x;tt[len].f=0;
 31     tt[len].next=first[y];first[y]=len;tt[len].o=len-1;
 32 }
 33 
 34 int ffind(int x)
 35 {
 36     if(fa[x]!=x) fa[x]=ffind(fa[x]);
 37     return fa[x];
 38 }
 39 
 40 queue<int > q;
 41 bool bfs()
 42 {
 43     while(!q.empty()) q.pop();
 44     memset(dis,-1,sizeof(dis));
 45     q.push(st);dis[st]=0;
 46     while(!q.empty())
 47     {
 48         int x=q.front();q.pop();
 49         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 50         {
 51             int y=t[i].y;
 52             if(dis[y]==-1)
 53             {
 54                 dis[y]=dis[x]+1;
 55                 q.push(y);
 56             }
 57         }
 58     }
 59     if(dis[ed]==-1) return 0;
 60     return 1;
 61 }
 62 
 63 int find_flow(int x,int flow)
 64 {
 65     if(x==ed) return flow;
 66     int now=0;
 67     for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 68     {
 69         int y=t[i].y;
 70         if(dis[y]==dis[x]+1)
 71         {
 72             int a=find_flow(y,mymin(t[i].f,flow-now));
 73             t[i].f-=a;
 74             t[t[i].o].f+=a;
 75             now+=a;
 76                 if(now==flow) break;
 77         }
 78     }
 79     if(now==0) dis[x]=-1;
 80     return now;
 81 }
 82 
 83 int max_flow()
 84 {
 85     int ans=0;
 86     while(bfs()) 
 87         ans+=find_flow(st,INF);
 88     return ans;
 89 }
 90 
 91 bool check(int x)
 92 {
 93     for(int i=1;i<=len;i++) t[i]=tt[i];
 94     for(int i=len-4*n+1;i<=len;i+=2) t[i].f=x;
 95     return max_flow()==n*x;
 96 }
 97 
 98 void finda()
 99 {
100     int l=0,r=n*n;
101     while(l<r)
102     {
103         int mid=(l+r+1)>>1;
104         if(check(mid)) l=mid;
105         else r=mid-1;
106     }
107     printf("%d\n",l);
108 }
109 
110 int main()
111 {
112     int T;
113     scanf("%d",&T);
114     while(T--)
115     {
116         len=0;
117         memset(first,0,sizeof(first));
118         memset(map,0,sizeof(map));
119         scanf("%d%d%d",&n,&m,&k);
120         for(int i=1;i<=m;i++)
121         {
122             int x,y;
123             scanf("%d%d",&x,&y);
124             map[x][y]=1;
125         }
126         for(int i=1;i<=n;i++) fa[i]=i;
127         for(int i=1;i<=k;i++)
128         {
129             int x,y;
130             scanf("%d%d",&x,&y);
131             fa[ffind(x)]=ffind(y);
132         }
133         for(int i=1;i<=n;i++)
134          for(int j=1;j<=n;j++) if(ffind(i)==ffind(j))
135          {
136              for(int k=1;k<=n;k++) if(map[j][k])
137               map[i][k]=1;
138          }
139         for(int i=1;i<=n;i++)
140          for(int j=1;j<=n;j++) if(map[i][j])
141             ins(i,j+n,1);
142         st=2*n+1;ed=st+1;
143         for(int i=1;i<=n;i++) ins(st,i,INF);
144         for(int i=1;i<=n;i++) ins(i+n,ed,INF);
145         finda();
146     }
147     return 0;
148 }
[HDU3081]

 

  所以现在我的数组是能开多大开多大。

 

2016-05-29 15:09:33

posted @ 2016-05-29 15:07  konjak魔芋  阅读(258)  评论(0编辑  收藏  举报