网络流学习:(最大流)POJ1149

题意:养猪场有M个猪圈,每个猪圈可以容纳的猪的数量没有限制.养猪场的工人没有钥匙,但是要买猪的客户有若干个猪圈的钥匙.当一个客户来买猪的时候他会把所有可以打开的猪圈打开,客户离开后工人可以将猪圈里剩余的猪分配到任意猪圈.工人预先知道客户的需求和所拥有的钥匙.问养猪场一天最多可以卖出多少头猪.
网络流的题目建图果然恶心….
建图:建立一个源点和一个汇点,如果一个客户i首先打开一个猪圈,将i与源点相连,容量为该猪圈的猪的数量;i后面紧接着有下一个客户j打开同一个猪圈的话,将i与j相连,容量为inf.每一个客户都与汇点相连,容量为该客户的需求.
建好图,直接用Dinic跑一遍就A了.刚看完Dinic算法,印象还是挺深的,没看模板写出来了.

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <queue>
#define MAX 1500
#define inf 10000000
using namespace std;
int level[MAX];//层次网络
int Map[MAX][MAX];//容量网络
bool vis[MAX];//判断猪圈是否被打开过
int N,M;

void Build_Map()
{
    int i,j,k,B;
    int Pnum[MAX];
    memset(vis,0,sizeof(vis));
    memset(Map,0,sizeof(Map));
    scanf("%d%d",&M,&N);
    for(i=1;i<=M;i++)
    {
        scanf("%d",&Pnum[i]);
    }
    for(i=1;i<=N;i++)
    {
        scanf("%d",&k);
        for(j=0;j<k;j++)
        {
            scanf("%d",&B);
            if(!vis[B])
            {
                Map[0][i]+=Pnum[B];
                Pnum[B]=i;
                vis[B]=1;
            }else
            {
                Map[Pnum[B]][i]=inf;
            }
        }
        scanf("%d",&B);
        Map[i][N+1]=B;
    }
}

bool BFS()
{
    queue<int> q;
    memset(level,0,sizeof(level));
    level[0]=1;
    q.push(0);
    while(!q.empty())
    {
        int v=q.front();
        q.pop();
        for(int i=0;i<=N+1;i++)
        {
            if(Map[v][i]&&!level[i])
            {
                level[i]=level[v]+1;
                q.push(i);
            }
        }
    }
    if(!level[N+1]) return false;
    else return true;
}

int DFS(int v,int sum)
{
    if(v==N+1) return sum;
    int s=sum;
    for(int i=0;sum&&i<=N+1;i++)
    {
        if(Map[v][i]&&level[v]+1==level[i])
        {
            int t=DFS(i,min(sum,Map[v][i]));
            Map[v][i]-=t;
            Map[i][v]+=t;
            sum-=t;
        }
    }
    return s-sum;
}


int main()
{
    Build_Map();
    int ans=0;
    while(BFS())
        ans+=DFS(0,inf);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值