POJ3281 Dining (SAP+GAP)

题目大意:农夫FJ的农场有一批奶牛,奶牛有自己喜爱的food和drink,FJ要计划一个策略,使得让尽可能多的牛匹配自己喜欢的food和drink,每种food和drink只能被分配一次,每头奶牛只能选择一种food和drink

思路:因为不是两个对象之间的匹配,所以不是最大匹配。是多个源点和多个汇点问题,所以可建立超级源点和超级汇点,从而利用网络流求最大流。sap~~79ms撸过~~把cin改掉应该能0ms吧~~嘿嘿

为了满足每头牛一个food和一个drink,要把牛拆开,其中的连线容量为1,我的图:0---->food----->牛前------->牛后------->drink----->f+2*n+d+1

 

 AC program:

#include<iostream>
#include<stdio.h> 
#include<string.h> 
#include<math.h>
#include<queue>  
#include<algorithm>
using namespace std;
#define inf 1000000000
#define maxn 450
#define maxm 21000  //note!! 如果RE就是这里出的原因 
int num;//note1 
int n,f,d;
struct node
{
  int c,next,to;       
}e[maxm]; //note2 
int box[maxn];//链式前向星 
void addee(int u,int v,int w)
{
    e[num].to=v;
    e[num].c=w;
    e[num].next=box[u];
    box[u]=num++;   
}
void init1()
{
  int u,v;
  for(int i=1;i<=f;i++)
  {
     u=0;v=i;
     addee(u,v,1);
     addee(v,u,0); 
      
  }       
}
void init2()
{
  int u,v; 
  for(int i=f+2*n+1;i<=f+2*n+d;i++)
  {
      u=i;v=f+2*n+d+1;
      addee(u,v,1);
      addee(v,u,0);        
  }     
}
void init3()
{
    int u,v;
    for(int i=f+1;i<=f+n;i++)
    {
       u=i;v=n+i;
       addee(u,v,1);
       addee(v,u,0);        
    }     
} 
void init4(int p)
{
  int ff,dd;
  cin>>ff>>dd;
  int food,drink;
  int u,v; 
  while(ff--)
  {
     cin>>food;
     u=food;
     v=f+p;
     addee(u,v,1);
     addee(v,u,0); 
             
  }    
  while(dd--)/// 
  {
      cin>>drink;
      u=f+n+p;v=f+n*2+drink;
      addee(u,v,1);
      addee(v,u,0);       
  }
}
int sap(int start,int end,int nnn)
{
  int numh[maxn],h[maxn],cur[maxn],pre[maxn];
  int cur_flow,flow_ans=0,u,tmp,neck,i;
  memset(h,0,sizeof(h)); 
   memset(numh,0,sizeof(numh));///
     memset(pre,-1,sizeof(pre));///
  for(int i=1;i<=nnn;i++)
     cur[i]=box[i];
  numh[0]=nnn;
  u=start;
  while(h[start]<nnn)
  {
      if(u==end)
      {
          cur_flow=inf;
          for(i=start;i!=end;i=e[cur[i]].to)
          {
              if(cur_flow>e[cur[i]].c)
              {
                neck=i;
                cur_flow=e[cur[i]].c;                        
              }                                  
          }
          for(i=start;i!=end;i=e[cur[i]].to)
          {
            tmp=cur[i];
            e[tmp].c-=cur_flow;
            e[tmp^1].c+=cur_flow;                                  
          }
          flow_ans+=cur_flow;
          u=neck;          
      }
      for(i=cur[u];i!=-1;i=e[i].next)
          if(e[i].c&&h[u]==h[e[i].to]+1) 
             break;
      if(i!=-1)
         {
               
           cur[u]=i;
           pre[e[i].to]=u;
           u=e[i].to;      
         }
      else
          {
            if(0==--numh[h[u]])break;
            cur[u]=box[u];
            for(tmp=nnn,i=box[u];i!=-1;i=e[i].next)
                if(e[i].c)
                    tmp=min(tmp,h[e[i].to]);
            h[u]=tmp+1;
            ++numh[h[u]];
            if(u!=start)u=pre[u];                 
                           
          } 
                                       
                        
  } 
  return flow_ans; 
} 
int main()
{
while(cin>>n>>f>>d)
{
  num=0;
  memset(box,-1,sizeof(box)); 
  init1();//超级源点和food
  init2();//超级汇点和drink
  init3();//牛和牛自身 
   for(int i=1;i<=n;i++)
  {
       init4(i); //牛前和food,牛后和drink      
  }     
  int love;
  love=sap(0,f+n*2+d+1,f+n*2+d+2);//f+n*2+d+2个点 
  printf("%d\n",love);                                         
} 
//system("pause"); 
return 0;} 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值