码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3281 网络流 拆点保证本身只匹配一对食物和饮料

时间:2019-08-10 17:43:49      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:void   奶牛   mes   eof   while   return   splay   show   typedef   

  如何建图?

  最开始的问题就是,怎么表示一只牛有了食物和饮料呢?

  后来发现可以先将食物与牛匹配,牛再去和饮料匹配,实际上这就构成了三个层次。

  起点到食物层边的容量是1,食物层到奶牛层容量是1,奶牛层到饮料层容量是1,饮料层到终点容量是1。

  但是后来发现有一组hack数据:

  2 3 3

  3 3 1 2 3 1 2 3
  3 3 1 2 3 1 2 3

  我们发现一头奶牛居然吃了多个套餐,所以要解决这个只需要将自己与自己建立一条容量是1的边就行了。

  

 

技术图片
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define sc scanf 
#define pt printf
#define maxe 40960
#define maxv 405
#define maxn 1000
#define mll long long
const int inf = 0x3f3f3f3f;
int mn(int a,int b) { return a<b?a:b; }
int  s,t, N,F,D;
typedef struct ed{
    int v,w,cap,flow;
} ed;
ed e[maxe];
int head[maxv],nxt[maxe],tot,dis[maxv];
void init()
{
    tot = 0 ; 
    memset(head,-1,sizeof(head));
}

void add(int u,int v,int cap,int flow)
{
    e[tot].v=v;
    e[tot].cap=cap; 
    e[tot].flow=flow;
    nxt[tot]=head[u];
    head[u]=tot++;

    e[tot].v=u;
    e[tot].cap=flow;        
    e[tot].flow=0;
    nxt[tot]=head[v];
    head[v]=tot++;
}
int dfs(int u,int exp)
{
    if(exp==0||u==t) return exp;
    int i,v,flow=0,tmp;
    for(i=head[u];i!=-1;i=nxt[i])
    {
        v=e[i].v;
        //pt("u=%d,v=%d\n",u,v);
        
        if(dis[v]==dis[u]+1)
        {
            tmp = dfs(v,mn(e[i].cap-e[i].flow,exp));
            if(tmp==0) continue;
            // pt("u=%d,v=%d,tmp=%d\n",u,v,tmp);
            e[i].flow +=   tmp;
            e[i^1].flow -= tmp;

            exp-=tmp;
            flow+=tmp;

            if(exp==0) break;
        }
    }
    //pt("wt\n");
    if(flow==0) dis[u]=inf;
    return flow;
}
stack<int> q;
int main()
{
    freopen("in.txt","r",stdin);
    while(~sc("%d%d%d",&N,&F,&D))
    {
        //pt("OK\n");
        int i,j,ans=0,u,v,tt,FF,DD;
        init(); s=0,t=1+2*N+F+D;
    //    pt("OK\n");
        // F使用1-F  N使用(F+1 - F+N)(F+1 + N - F+ 2*N)  D使用 F+2*N+1 - F+2*N+D
        for(i=1;i<=F;++i) add(0,i,1,0);
        for(i=F+2*N+1;i<=F+2*N+D;++i) add(i,t,1,0);
        for(i=F+1;i<=F+N;++i) add(i,i+N,1,0);
        //pt("OK\n");
        for(i=1;i<=N;++i)
        {
            sc("%d%d",&FF,&DD);
            for(j=1;j<=FF;++j)
            {
                sc("%d",&tt);
                add(tt,F+i,1,0);
            }  
            for(j=1;j<=DD;++j)
            {
                sc("%d",&tt);
                add(F+N+i,F+2*N+tt,1,0);
            }  
        }
        //pt("OK\n");
        while(1)
        {
            //BFS建立层次图
            memset(dis,inf,sizeof(dis));
            dis[s]=0; 
            while(!q.empty()) q.pop();
            q.push(s);
            while(!q.empty())
            {
                
                u=q.top(); q.pop();
                for(i=head[u];i!=-1;i=nxt[i])
                {
                    if(e[i].cap - e[i].flow <= 0) continue;
                    v = e[i].v;
                    
                    if(dis[u]+1<dis[v])
                    {
                        dis[v] = dis[u] +1;
                        //pt("BFS: u=%d,v=%d\n",u,v);
                        if(v==t) break;
                        q.push(v);
                    } 
                    
                }
            }
            if(dis[t]==inf) break;
            //DFS进行增广
            tt=dfs(0,inf);
            if(tt==0) break;
            else ans+=tt;
            //pt("tt=%d\n",tt);
            
        }
        pt("%d\n",ans);
    }
    return 0;
}
POJ 3281

 

POJ 3281 网络流 拆点保证本身只匹配一对食物和饮料

标签:void   奶牛   mes   eof   while   return   splay   show   typedef   

原文地址:https://www.cnblogs.com/lighten-up-belief/p/11332102.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!