poj 3281

      网络流的构图题。构图时设立超级源点和超级汇点。源点与每个食物连一条容量为1的边,汇点与每个饮料连一条容量为1的边。牛要拆点,入点与对应的食物连容量为1的边,出点和对应的饮料连一条容量为1的边。入点和出点间连一条容量的边。这样才能充分利用限制条件。最后求一次最大流即可。

 

      构图题往往难度不大,只要充分利用已知的限制条件构造出图,套个模版即可。但构图的技巧很多,需要慢慢积累,大部分的网络流模型都很隐蔽,不是那么容易就看得出来的。

 

      以下是代码:

  1. #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int M=1000100;
    const int N=1000;
    const int INF=1<<29;
  2. struct node
    {
     int u,v,cap,flow;
     int next;
    }edge[M];
    int head[N],num;
    int level[N];
    int n,f,d,s,t;
  3. void init()
    {
     int i;
     for(i=0;i<=2*n+f+d+5;i++)
      head[i]=-1;
     num=0;
     s=0;t=2*n+f+d+1;
    }
  4. void addege(int u,int v,int cap)
    {
     edge[num].u=u;
     edge[num].v=v;
     edge[num].cap=cap;
     edge[num].flow=0;
     edge[num].next=head[u];
     head[u]=num++;
     edge[num].u=v;
     edge[num].v=u;
     edge[num].cap=0;
     edge[num].flow=0;
     edge[num].next=head[v];
     head[v]=num++;
    }
  5. int dinic_dfs(int sta,int end,int ver)
    {
     int stack[N*10],top=0;
     int flow=0,cur,ptr,pre[N],minf,i;
     int del[N];
     for(i=0;i<=ver;i++)
     {
      del[i]=0;
     }
     stack[top++]=sta;
     pre[sta]=sta;
     cur=sta;
     while(top)
     {
      while(cur!=end && top)
      {
       for(i=head[cur];i!=-1;i=edge[i].next)
       {
        int v=edge[i].v;
        if(level[v]==level[cur]+1 && edge[i].cap>edge[i].flow && !del[v])
        {
         stack[top++]=v;
         cur=v;
         pre[v]=i;
         break;
        }
       }
       if(i==-1)
       {
        del[cur]=1;
        top--;
        if(top)
         cur=stack[top-1];
       }
      }
      if(cur==end)
      {
       minf=INF;
       while(cur!=sta)
       {
        cur=pre[cur];
        if(edge[cur].cap-edge[cur].flow<minf) minf=edge[cur].cap-edge[cur].flow;
        cur=edge[cur].u;
       }
       cur=end;
       while(cur!=sta)
       {
        cur=pre[cur];
        edge[cur].flow+=minf;
        edge[cur^1].flow-=minf;
        if(edge[cur].cap-edge[cur].flow==0)
        {
         ptr=edge[cur].u;
        }
        cur=edge[cur].u;
       }
       while(top>0 && stack[top-1]!=ptr) top--;
       if(top) cur=stack[top-1];
       flow+=minf;
      }
     }
     return flow;
    }
  6. bool dinic_bfs(int sta,int end,int ver)
    {
     int queue[10*N];
     int i,j;
     for(i=0;i<=ver;i++)
     {
      level[i]=-1;
     }
     int rear=0;
     queue[rear++]=sta;
     level[sta]=0;
     for(i=0;i<rear;i++)
     {
      for(j=head[queue[i]];j!=-1;j=edge[j].next)
      {
       int v=edge[j].v;
       if(level[v]==-1 && edge[j].cap>edge[j].flow)
       {
        level[v]=level[queue[i]]+1;
        queue[rear++]=v;
       }
      }
     }
     return level[end]>=0;
    }
  7. int dinic(int sta,int end,int ver)
    {
     int flow=0,t;
     while(dinic_bfs(sta,end,ver))
     {
      t=dinic_dfs(sta,end,ver);
      if(t) flow+=t;
      else break;
     }
     return flow;
    }
  8. int main()
    {
     scanf("%d%d%d",&n,&f,&d);
     int i,j;
     init();
     for(i=1;i<=f;i++)
      addege(s,i,1);
     for(i=f+2*n+1;i<t;i++)
      addege(i,t,1);
     for(i=f+1;i<=f+n;i++)
     {
      addege(i,i+n,1);
      int a,b,c;
      scanf("%d%d",&a,&b);
      for(j=0;j<a;j++)
      {
       scanf("%d",&c);
       addege(c,i,1);
      }
      for(j=0;j<b;j++)
      {
       scanf("%d",&c);
       addege(i+n,f+2*n+c,1);
      }
     }
     printf("%d/n",dinic(s,t,t+1));
     return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值