HDOJ 3277 - Marriage Match III 拆点构图最大流..偷了一个效率很好的Dinic....

                  题意:

                           有N个女孩和N个男孩玩过家家...某些女孩之间存在朋友关系..并且朋友关系可以传递.比如a和b是朋友..b和c是朋友...那么a,c就会是朋友...首先每个女生可以选男生做男友并且这个男生至少和她朋友圈包括自己的某个女孩从没吵过架...在一个每个女生可以和有吵架关系的K个男生谈朋友...每一轮进行一次配对...每轮必须每对都不同..问最多可以配对多少轮...

                  题解:

                           和HDOj3081不同的是..枚举了当前的轮数M后...对于每个女孩.拆成两个点..一个点A为要选择合适的男生..一个点B为要选择不合适的男生..超级源点到所有的A做边容量为M..所有的A对其B做边,容量为K...所有的B对超级汇点做边..容量为M...然后再根据关系加边....

                           我的dinic超时啊...没得救了...T_T...上周撸了一个比较厉害的dinic....          


Program:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define MAXN 2005
#define MAXM 100005
#define oo 1000000007
#define ll long long
using namespace std;  

struct Dinic  
{  
       struct node
       { 
             int c,u,v,next;
       }edge[MAXM];
       int ne,head[MAXN];
       int cur[MAXN], ps[MAXN], dep[MAXN];
       void initial()
       {
             ne=2;
             memset(head,0,sizeof(head)); 
       }
       void addedge(int u, int v,int w)
       { 
             edge[ne].u=u,edge[ne].v=v,edge[ne].c=w,edge[ne].next=head[u];
             head[u]=ne++;
             edge[ne].u=v,edge[ne].v=u,edge[ne].c=0,edge[ne].next=head[v];
             head[v]=ne++;
       }
       int MaxFlow(int s,int t)
       {                     
             int tr, res = 0;
             int i,j,k,f,r,top;
             while(1)
             {
                    memset(dep, -1, sizeof(dep));
                    for(f=dep[ps[0]=s]=0,r=1;f!= r;)
                       for(i=ps[f++],j=head[i];j;j=edge[j].next)
                         if(edge[j].c&&dep[k=edge[j].v]==-1)
                         {
                               dep[k]=dep[i]+1;
                               ps[r++]=k;
                               if(k == t){  f=r; break;  }
                         }
                    if(dep[t]==-1) break;
                    memcpy(cur,head,sizeof(cur));
                    i=s,top=0;
                    while(1)
                    {
                         if(i==t)
                         {
                               for(tr=oo,k=0;k<top;k++)
                                  if(edge[ps[k]].c<tr)
                                     tr=edge[ps[f=k]].c;
                               for(k=0;k<top;k++)
                               {
                                     edge[ps[k]].c-=tr;
                                     edge[ps[k]^1].c+=tr;
                               }
                               i=edge[ps[top=f]].u;
                               res+= tr;
                         }
                         for(j=cur[i];cur[i];j=cur[i]=edge[cur[i]].next) 
                             if(edge[j].c && dep[i]+1==dep[edge[j].v]) break; 
                         if(cur[i])  ps[top++]=cur[i],i=edge[cur[i]].v; 
                         else
                         {
                                 if(!top) break;
                                 dep[i]=-1;
                                 i=edge[ps[--top]].u;
                         }
                   }
             }
             return res;
      }
}T;   
int father[305];
bool g[305][305];
int getfather(int x)
{
      if (father[x]==x) return x;
      return father[x]=getfather(father[x]);
}
bool judge(int n,int K,int M)
{ 
      int i,j,s=n<<2,e=s+1,u=n<<1|1;
      T.initial();
      for (i=0;i<n;i++)
          T.addedge(s,i<<1,M),T.addedge(i<<1,i<<1|1,K),T.addedge(u+i,e,M); 
      for (i=0;i<n;i++)
         for (j=0;j<n;j++) 
            if (g[father[i]][j]) 
              T.addedge(i<<1,u+j,1); 
                else T.addedge(i<<1|1,u+j,1);  
      return T.MaxFlow(s,e)==n*M;
}
int main() 
{      
      int C,cases,n,m,f,K,i,j,x,y; 
      freopen("input.txt","r",stdin);
      freopen("output.txt","w",stdout);
      scanf("%d",&C);
      for (cases=1;cases<=C;cases++)
      {
               scanf("%d%d%d%d",&n,&m,&K,&f);
               memset(g,false,sizeof(g));
               while (m--)
               {
                        scanf("%d%d",&x,&y);
                        g[--x][--y]=true;
               }
               for (i=0;i<n;i++) father[i]=i;
               while (f--)
               {
                        scanf("%d%d",&x,&y),x=getfather(--x),y=getfather(--y);
                        father[x]=y;
                        for (i=0;i<n;i++) g[y][i]=g[y][i]|g[x][i];
               }               
               for (i=0;i<n;i++) getfather(i);           
               int l=0,r=n+1,mid;
               while (r-l>1)
               {
                        mid=l+r>>1;
                        if (judge(n,K,mid)) l=mid;
                                      else  r=mid; 
               }
               printf("%d\n",l);
      }
      return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值