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

  如何建图?

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

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

  起点到食物层边的容量是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

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

时间: 2024-10-08 20:17:23

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

POJ 3281 网络流 拆点 Dining

题意: 有F种食物和D种饮料,每头牛有各自喜欢的食物和饮料,而且每种食物或者饮料只能给一头牛. 求最多能有多少头牛能同时得到它喜欢的食物或者饮料. 分析: 把每个牛拆点,中间连一条容量为1的边,保证一头牛不会被多个食物或者饮料分配. 然后把饮料和牛连边,食物和另外一边的牛连边,最后增加一个源点和汇点跑最大流. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <alg

POJ 3281 网络流(dinic邻接矩阵、单路增广、多路增广)

思路:刚开始看题就想到怎么建图了,源点连向所有的食物,食物连牛,牛连饮料,饮料连汇点,所有的流量都是1.不过这样建图好后,WA了.原来是一头牛只能单一匹配一组食物和饮料,所以牛得拆点,牛之间得相连,流量为1,以保证单一匹配食物和饮料. 邻接矩阵dinic单路的代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #in

POJ 3281 网络流dinic算法

B - Dining Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3281 Appoint description: Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she wil

POJ 3281【拆点 &amp;&amp; 最大流经典建图】

Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11097   Accepted: 5096 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has cooked fabulo

POJ 3281 Dining (拆点)【最大流】

<题目链接> 题目大意: 有N头牛,F种食物,D种饮料,每一头牛都有自己喜欢的食物和饮料,且每一种食物和饮料都只有一份,让你分配这些食物和饮料,问最多能使多少头牛同时获得自己喜欢的食物和饮料. 解题分析: 开始还以为是一道匹配问题,后面才知道这是用网络流求解. 首先我们要明确,如果按照源点——>食物——>牛——>饮料——>汇点这样建图,是不符合题目条件的.因为题目要求每头牛只能吃一份食物和饮料,而这样建图,如果一头牛对应多个食物和饮料,那这样那头牛是可以吃多份食物和饮料

ACM Computer Factory POJ - 3436 网络流拆点+路径还原

每台电脑有p个组成部分,有n个工厂加工电脑. 每个工厂对于进入工厂的半成品的每个组成部分都有要求,由p个数字描述,0代表这个部分不能有,1代表这个部分必须有,2代表这个部分的有无无所谓. 每个工厂的产出也不尽相同,也是由p个数字代表,0代表这个部分不存在,1代表这个部分存在.每个工厂都有一个最大加工量. 给出这n个工厂的数据,求出最多能加工出多少台电脑 对于容量有限制,因此拆点 开始的机器没有零件,连接符合要求的点 最终的机器应该是完整的,把符合要求的点连接到汇点 因为已经拆过点限制了流量,所以

B - Dining POJ - 3281 网络流

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not

POJ 3281 Dining(最大流建图 &amp;&amp; ISAP &amp;&amp; 拆点)

题目链接:http://poj.org/problem?id=3281 努力练建图ing!!! 题意:有 N 头牛,有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料. 第2行-第N+1行.是牛i 喜欢A种食物,B种饮料,及食物种类列表和饮料种类列表. 问最多能使几头牛同时享用到自己喜欢的食物和饮料.->最大流. 本题难点是建图: 思路:一般都是左边一个集合表示源点与供应相连,右边一个集合表示需求与汇点相连. 但是本题,牛作为需求仍然是一个群体,但是供

Poj 2391 Ombrophobic Bovines 网络流 拆点

Poj 2391 Ombrophobic Bovines 网络流 拆点 FJ's cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They have decided to put a rain siren on the farm to let them know when rain is approa