[Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining

传送门:https://www.luogu.org/problemnew/show/P2891

题面

\

Solution

网络流

先引用一句真理:网络流最重要的就是建模

今天这道题让我深有体会

首先,观察数据范围,n=100,一般这种100-1000的图论题,很有可能是网络流.

那就直接从网络流的角度入手

考虑这样建模

建模要点如下:

1.建权值为1的边,保证每个食物和水仅用一次

 2.没了

对以上的图求一个最大流,那不就是我们想要的最大的匹配数吗?

看起来是不是很OjbK?

其实不然,这样子一头牛有可能脚踏N条食物和水,但是题目要求一头牛只能吃喝一次

反例如下:

所以说,我们要对一头牛吃的东西做一个限制,保证其只流过1

怎么限制呢?

直接把一头牛拆成两头牛,中间连一条边就OK了嘛

如下图:

接下来就可以考虑如何给点编号了

我的编号方法很直接,很暴力

源点:1

食物: 2 ~  2+f-1

牛   2+f ~ 2+f+2n -1

水: 2+f+2n ~ 2+f+2n+d

汇点:1000

如下图所示

按照以上方法,每种物品对应的点为:

食物i : 1+i

牛i : 1+f+i

牛i的右边的分点:  1+f+n+i

水i: 1+f+2*n+i

然后dinic直接求一波最大流就可以带走啦

DINIC教程传送门: http://www.cnblogs.com/SYCstudio/p/7260613.html (个人感觉写得很清楚)

Code

//Luogu P2891 [USACO07OPEN]吃饭Dining
//Apr,2ed,2018
//Dinic求最大流
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c==‘-‘) f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}
const int N=100+10;
const int M=N*10;
const int inf=0x3f3f3f3f;
struct line
{
    int t,rev,w;
};
vector <line> e[M];
inline void AddLine(int s,int t)
{
    line temp;
    temp.t=t,temp.rev=e[t].size(),temp.w=1;
    e[s].push_back(temp);
    temp.t=s,temp.rev=e[s].size()-1,temp.w=0;
    e[t].push_back(temp);
}
int n,f,d;
int dl[M],head,tail,depth[M];
bool visited[M];
bool bfs()
{
    memset(visited,0,sizeof visited);
    dl[1]=1,depth[1]=1;
    visited[1]=true;
    head=1,tail=2;
    while(head<tail)
    {
        int now=dl[head],size=e[now].size();
        for(int i=0;i<size;i++)
            if(visited[e[now][i].t]==false and e[now][i].w>0)
            {
                visited[e[now][i].t]=true;
                dl[tail++]=e[now][i].t;
                depth[e[now][i].t]=depth[now]+1;
            }
        head++;
    }
    return visited[1000];
}
int dfs(int now,int f)
{
    if(now==1000)
        return f;
    int size=e[now].size(),ans=0;
    for(int i=0;i<size;i++)
        if(depth[e[now][i].t]==depth[now]+1 and e[now][i].w>0)
        {
            int t_ans=dfs(e[now][i].t,min(f,e[now][i].w));
            e[now][i].w-=t_ans;
            e[e[now][i].t][e[now][i].rev].w+=t_ans;
            f-=t_ans,ans+=t_ans;
            if(f==0) break;
        }
    return ans;
}
int Dinic()
{
    int ans=0;
    while(bfs())
        ans+=dfs(1,inf);
    return ans;
}
int main()
{
    n=read(),f=read(),d=read();
    for(int i=1;i<=1000;i++)
        e[i].reserve(16);
    for(int i=1;i<=f;i++)
        AddLine(1,1+i);
    for(int i=1;i<=d;i++)
        AddLine(1+f+2*n+i,1000);
    for(int i=1;i<=n;i++)
    {
        int F=read(),D=read(),temp;
        for(int j=1;j<=F;j++)
        {
            temp=read();
            AddLine(1+temp,1+f+i);
        }
        for(int j=1;j<=D;j++)
        {
            temp=read();
            AddLine(1+f+n+i,1+f+2*n+temp);
        }
    }
    for(int i=1;i<=n;i++)
        AddLine(1+f+i,1+f+n+i);

    printf("%d",Dinic());
    return 0;
}

C++

后记

写的时候发现自己真的有点生疏了,这种比较靠记忆的算法还是久不久搞一下来恢复记忆为妙

网络流的时间复杂度真玄学

原文地址:https://www.cnblogs.com/GoldenPotato/p/8697971.html

时间: 2024-08-30 17:42:32

[Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining的相关文章

P2891 [USACO07OPEN]吃饭Dining(最大流+拆点)

题目描述 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 migh

洛谷P2891 [USACO07OPEN]吃饭Dining

题目描述 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 migh

poj 3281 Dining(最大流)

poj 3281 Dining 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 fabulous meals for his cows, but he forgot to check his menu against their prefer

POJ 3281 Dining(网络最大流)

http://poj.org/problem?id=3281 Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9121   Accepted: 4199 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

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 3281 Dining(最大流)

POJ 3281 Dining 题目链接 题意:n个牛,每个牛有一些喜欢的食物和饮料,每种食物饮料只有一个,问最大能匹配上多少只牛每个牛都能吃上喜欢的食物和喜欢的饮料 思路:最大流,建模源点到每个食物连一条边,容量为1,每个饮料向汇点连一条边容量为1,然后由于每个牛有容量1,所以把牛进行拆点,然后食物连向牛的入点,牛的出点连向食物,跑一下最大流即可 代码: #include <cstdio> #include <cstring> #include <queue> #in

POJ 2438 Children&#39;s Dining(哈密顿回路)

题目链接:http://poj.org/problem?id=2438 题意: 有2*N个小朋友要坐在一张圆桌上吃饭,但是每两个小朋友之间存在一种关系,即敌人或者朋友,然后需要让你安排一个座位次序,使得相邻的两个小朋友都不会是敌人.假设每个人最多有N-1个敌人.如果没有输出"No solution!". 思路: 如果按照题意直接建图,每个点表示一个小朋友,小朋友之间的敌对关系表示两个点之间有边.问题是求小朋友围着桌子的座次就是求图中的一个环,但是要求这个环不能包含所给出的每条边,所有没

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 2438 Children&#39;s Dining

http://poj.org/problem?id=2438 题意: 有2*N个人要坐在一张圆桌上吃饭,有的人之间存在敌对关系,安排一个座位次序,使得敌对的人不相邻. 假设每个人最多有N-1个敌人.如果没有输出"No solution!". 如果i和j可以相邻,之间连一条边 每个人最多有N-1个敌人,所以每个人至少会连出去N+1条边 根据狄拉克定理,图一定是哈密顿图 所以本题不存在无解的情况 然后输出一条哈密顿回路就好了 有关哈密顿图与哈密顿回路的问题 参见文章 http://www.