pku 3281

//3281 Accepted 236K 32MS C++ 2422B
//源点到食物连一条为1的边 汇点到饮料连一条边
//牛分成两排  左牛和右牛 牛和牛之间连一条为1的边   这样的好处是可以限制牛的 使用数量
//如果牛只有一排 则没法办法控制牛的重复计算 左牛1..N 右牛N+1...2*N 
//食物  2*N + 1 ... 2*N + F 后面为饮料  源点0 汇点 2*N + F + D + 1
#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
using namespace std;
const int V = 520;
const int E = 50005;
struct Edge{
 int u,v,c;
 int next;
}edg[E];
int head[V],dis[V],temp[V],stack[V];
int N,F,D,e,src,End;
inline void addadge(int u,int v,int c)
{
 edg[e].u = u; edg[e].v = v; edg[e].c = c;
 edg[e].next = head[u]; head[u] = e++;
}
int bfs()
{
 queue<int>q;
 q.push(src);
 int now,i,v,c;
 memset(dis,-1,sizeof(dis));
 dis[src] = 0;
 while(!q.empty())
 {
  now  = q.front();
  q.pop();
  for(i = head[now]; i != -1; i = edg[i].next)
  {
   v = edg[i].v;
   c = edg[i].c;
   if(dis[v] == -1 && c > 0)
   {
    dis[v] = dis[now] + 1;
    q.push(v);
   }
  }
 }
 return (dis[End] >= 0);
}
int dinic()
{
 int ret = 0;
 int u,v,c,i,top,min,t;
 while(bfs())
 {
  memcpy(temp,head,sizeof(temp));
  u = src;top = 0;
  while(1){
   if(u == End){
    t = INT_MAX;min = -1;
    for(i = 0; i < top; i++){
     if(edg[stack[i]].c < t){
      t = edg[stack[i]].c;
      min = i;
     }
    }
    ret += t;
    for(i = 0; i < top; i++){
     v = stack[i];
     edg[v].c -= t;
     edg[v^1].c += t;
    }
    top = min;
    u = edg[stack[top]].u;
   }
   for(i = temp[u]; i != -1; i = edg[i].next){
    v = edg[i].v;
    c = edg[i].c;
    if(dis[v] == dis[u] + 1 && c > 0)
    break;
   }
   if(i != -1){
    stack[top++] = i;
    temp[u] = i;
    u = edg[i].v;
   }
   else{
    if(top <= 0)break;
    top--;
    dis[u] = -1;
    u = edg[stack[top]].u;
   }
  }
 }
 return ret;
}
void solve()
{
 int i,s,t,fn,dn,j,k;
 while(scanf("%d %d %d",&N,&F,&D) != EOF)
 {
  memset(head,-1,sizeof(head));
  e = 0;src = 0;End = 2*N + F + D + 1;
  for(i = 1; i <= F; i++)
  {
   addadge(src,i + 2*N,1);  //源点到食物
   addadge(i + 2*N,src,0);  
  }
  for(i = 1; i <= D; i++)
  {
   addadge(i + 2*N + F,End,1);
   addadge(End,i + 2*N + F,0); //汇点与饮料
  }
  for(i = 1; i <= N; i++)
  {
   addadge(i,i + N,1);  //左牛到右牛
   addadge(i + N,i,0);
   scanf("%d %d",&fn,&dn);
   for(j = 1; j <= fn; j++)
   {
    scanf("%d",&t);
    t += 2*N;
    addadge(t,i,1);
    addadge(i,t,0);//左牛与食物
   }
   for(j = 1; j <= dn; j++)
   {
    scanf("%d",&t);
    t += 2*N + F;
    addadge(i + N,t,1);
    addadge(t,i + N,0);//右牛 与 饮料
   }
  }
  printf("%d/n",dinic());
 }
}
int main()
{
 solve();
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值