USACO Section 4.2 The Perfect Stall - 网络流求最大二分图匹配..



    用网络流求二分图匹配的方法在算法导论上就看到过了..只是一直没去实现..确实用网络流来解二分图匹配有点大材小用了..一般的求最大匹配用匈牙利算法轻轻松松一分钟啊..但是网络流的解法虽然写起来多..但思想也是很简单的...对二分图左边加一个超级源点...超级源点对左边所有点做一条容量为1的边..右边给个超级汇点..右边所有点对超级汇点做一条容量为1的边..而左边所有点的点按照所给的关系对右边做边..容量都为1...这里注意题目给的左边点标号为1~N..右边点为1~M.为了区分左右点..可以将右边点标号看成N+1~N+M...

    构好图后跑一遍从超级源点到超级汇点的最大流就是结果了... 


Program:

/*  
ID: zzyzzy12   
LANG: C++   
TASK: stall4
*/      
#include<iostream>      
#include<istream>  
#include<stdio.h>      
#include<string.h>      
#include<math.h>      
#include<stack>
#include<map>
#include<algorithm>      
#include<queue>   
#define oo 1000000000  
#define ll long long  
#define pi (atan(2)+atan(0.5))*2 
using namespace std;
struct node
{
      int x,y,c,next; 
}line[10001];
int n,m,MaxFlow,_link[501],way[501],dis[501],dep;
bool used[501],f;
queue<int> myqueue;
bool BFS()
{ 
      int i,h,k;
      while (!myqueue.empty()) myqueue.pop();
      memset(used,false,sizeof(used));
      for (i=0;i<=n;i++) dis[i]=oo;
      dis[0]=0; myqueue.push(0);
      while (!myqueue.empty())
      {
            h=myqueue.front();
            myqueue.pop();
            k=_link[h];
            while (k)
            {
                  if (line[k].c && dis[line[k].y]>dis[h]+1)
                  {
                          dis[line[k].y]=dis[h]+1;
                          if (!used[line[k].y])
                          {
                                 myqueue.push(line[k].y);
                                 used[line[k].y]=true;                    
                          }              
                  }
                  k=line[k].next;     
            }            
      }
      return dis[n]!=oo;          
}
void DFS(int p)
{
      int i,k;
      if (p==n)
      { 
            for (i=1;i<=dep;i++)
            {
                   m++;
                   line[m].x=line[way[i]].y; line[m].y=line[way[i]].x;
                   line[m].c=1; 
                   line[m].next=_link[line[m].x]; _link[line[m].x]=m;
                   line[way[i]].c=0;
            }
            MaxFlow++;
            f=true;
            return;         
      }  
      k=_link[p];
      used[p]=true;
      while (k)
      {
            if (!used[line[k].y] && line[k].c && dis[line[k].y]-dis[line[k].x]==1)
            {
                   way[++dep]=k;              
                   DFS(line[k].y);   
                   dep--;      
                   if (f) return;        
            }
            k=line[k].next;
      }
      used[p]=false;
      return;  
} 
void Dinic()
{
      MaxFlow=0;
      while (BFS())
      {
            memset(used,false,sizeof(used));  
            dep=0; f=false;
            DFS(0);
      }    
}
int main()  
{  
      freopen("stall4.in","r",stdin);   
      freopen("stall4.out","w",stdout); 
      scanf("%d%d",&n,&m);
      int i,x,y,num;
      memset(_link,0,sizeof(_link));
      num=0;
      for (x=1;x<=n;x++)
      {
            scanf("%d",&i);
            while (i--)
            {
                  num++;
                  scanf("%d",&y); y+=n;
                  line[num].x=x; line[num].y=y; line[num].c=1; 
                  line[num].next=_link[x]; _link[x]=num;
            }          
      }
      for (y=1;y<=n;y++)
      {
            num++;
            line[num].x=0; line[num].y=y; line[num].c=1;
            line[num].next=_link[0]; _link[0]=num;   
      }
      for (x=n+1;x<=n+m;x++)
      {
            num++;
            line[num].x=x; line[num].y=n+m+1; line[num].c=1;
            line[num].next=_link[x]; _link[x]=num;    
      }
      n=m+n+1; m=num; 
      Dinic();
      printf("%d\n",MaxFlow);
      return 0;     
}   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值