POJ 3281 浅谈网络流基础建模

本文介绍了一个典型的最大流问题实例——如何通过构建适当的图模型解决牛与食物及饮料的匹配问题。文章详细阐述了问题背景、建模思路以及具体实现代码,帮助读者理解最大流问题的应用场景和解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
世界真的很大
这道题其实很水的
但是不知怎么的今天poj太卡了
等了好久结果才出来,还好一遍A了,不然不知道还要等多久
看题先:
description:

农夫为他的 N (1N100) 牛准备了 F (1 ≤ F ≤ 100)种食物和 D (1D100) 种饮料。每头牛都有各自喜欢的食物和饮料,而每种食物或饮料只能分配给一头牛。最多能有多少头牛可以同时得到喜欢的食物和饮料?

input

第一行输入三个整数N, F, D
接下来n行,每行先输入两个整数 Fi 和 Di,分别表示编号为 i 的牛喜欢的食物和饮料的数量,接下来的Fi个整数表示第i头牛喜欢的食物的编号,最后Di个整数表示第i头牛喜欢的饮料的编号。

output

输出同时得到喜欢的食物和饮料的牛的数量的最大值。

题其实很简单的,但还是浅谈一下
题目给出了几种project之间的依赖关系,求最大匹配数
明确是最大流问题
每头牛有喜欢的饮料和食物,摆明了食物向牛建边,牛向饮料建边,边权为INF,因为不做限制条件
每种食物只有一个,源点向食物连边,边权为1,限制食物数目
每种饮料只有一个,饮料向汇点连边,边权为1,限制饮料数目
又因为每头牛只能吃一套饮料和食物,所以牛拆点建一条边权为1的边,以限制牛吃套餐的数量
不同物品间用数量区别开就好
完整代码:

#include<stdio.h>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;

struct edge
{
    int v,last,w;
}ed[100010];

queue <int> state;

int head[100010],dis[100010];
int ans=0,num=1,S,T,F,D,n;

void add(int u,int v,int w)
{
    num++;
    ed[num].v=v;
    ed[num].w=w;
    ed[num].last=head[u];
    head[u]=num;
}

bool bfs()
{
    while(state.size()) state.pop();
    memset(dis,-1,sizeof(dis));
    dis[S]=0;
    state.push(S);
    while(!state.empty())
    {
        int u=state.front();
        state.pop();
        for(int i=head[u];i;i=ed[i].last)
        {
            int v=ed[i].v;
            if(dis[v]==-1&&ed[i].w>0)
            {
                dis[v]=dis[u]+1;
                state.push(v);
            }
        }
    }
    if(dis[T]==-1) return 0;
    return 1;
}

int dfs(int u,int low)
{
    if(u==T || low==0) return low;
    int a=0;
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(ed[i].w>0&&dis[v]==dis[u]+1)
        {
            int tmp=dfs(v,min(low,ed[i].w));
            ed[i].w-=tmp;
            ed[i^1].w+=tmp;
            a+=tmp,low-=tmp;
            if(low==0) return a;
        }
    }
    if(low) dis[u]=-1;
    return a;
}

int main()
{
    scanf("%d%d%d",&n,&F,&D);
    S=0,T=F+n+n+D+1;
    for(int i=1;i<=n;i++)
    {
        int a,b,x;
        scanf("%d%d",&a,&b);
        add(i+F,i+F+n,1);
        add(i+F+n,i+F,0);

        for(int j=1;j<=a;j++)
        {
            scanf("%d",&x);
            add(x,i+F,INF);
            add(i+F,x,0);
        }
        for(int j=1;j<=b;j++)
        {
            scanf("%d",&x);
            add(i+F+n,x+F+n+n,INF);
            add(x+F+n+n,i+F+n,0);
        }
    }
    for(int i=1;i<=F;i++)
    {
        add(S,i,1);
        add(i,S,0);
    }
    for(int i=1;i<=D;i++)
    {
        add(F+n+n+i,T,1);
        add(T,F+n+n+i,0);
    }
    while(bfs())
         ans+=dfs(S,INF);
    printf("%d\n",ans);
    return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/

嗯,就是这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值