POJ 1149

116 篇文章 2 订阅
32 篇文章 0 订阅

题目:

m个猪圈,n个顾客,每个猪圈里面有一定数量的猪,每个顾客有一定的需求量。求最多可以卖出多少条猪?

这里注意有一个前提条件,就是一个顾客开了一个猪圈之后,后 面的话,可以将这个猪圈里面的猪 拉到其他猪圈里去。

此题关键就是 建立图结构,因为最大流问题,我们可以用 EK 模板来套。

此图里面有三层,第一层就是源点,第二层顾客,第三层是汇点。

总的来说,源点与顾客连,顾客与汇点连。注意,猪圈不在图里面。

顾客与汇点连的话,权值就是 顾客所需要的猪的数量,比较好理解。

源点与顾客连,前提是 该顾客是第一个开某个猪圈的人。 然后,将该顾客连向后面也需要开此猪圈的人,权值为MAX

我的理解是,第一个打开猪圈的客户可以取得所有的猪,故源点和客户之间的连线容量就表示第一个打开猪圈的人虽能够得到的数量..


然后接下来的每一个人与前一个打开猪圈的人之间连线,容量为MAX,因为可以从别的猪圈调猪过来

一开始,总是  Runtime error,以为是超时,后来发现算法没问题。最后查出来发现,是因为 pre数组开小了。


#include <iostream>
#include <queue>
using namespace std;

#define MAXV 110
#define PIGNUM 1005
#define MAX 1<<29
int map[MAXV][MAXV];
int pre[PIGNUM];
int flow[MAXV];
int n;

queue<int>q;

int BFS(){
    int i;
    memset(pre,-1,sizeof(pre));
    while(!q.empty())
        q.pop();
    pre[0] = 0;
    flow[0] = MAX;
    q.push(0);
    while(!q.empty()){
        int index = q.front();
        q.pop();
        if(index == n+1)
            break;
        for(i=1;i<=n+1;i++){
            if(map[index][i]>0&&pre[i]==-1){
                pre[i] = index;
                flow[i] = min(flow[index],map[index][i]);
                q.push(i);
            }
        }
    }
    if(pre[n+1]==-1)
        return -1;
    else
        return flow[n+1];
}

int maxFlow(){
    int increasement = 0;
    int sumflow = 0;
    while((increasement = BFS())!=-1){
        int k = n+1;
        while(k!=0){
            int last = pre[k];
            map[last][k] -= increasement;
            map[k][last] += increasement;
            k = last;
        }
        sumflow += increasement;
    }
    return sumflow;
}

int main(){
    int m,i,j,k;
    int pigNum[PIGNUM];
    while(cin>>m>>n){
        memset(map,0,sizeof(map));
        for(i=1;i<=m;i++)
            cin>>pigNum[i];
        for(i=1;i<=n;i++){
            cin>>j;
            while(j--){
                cin>>k;
                if(pre[k] == 0)
                    map[0][i] += pigNum[k];
                else
                    map[pre[k]][i] = MAX;
                pre[k] = i;
            }
            cin>>map[i][n+1];
        }
        cout<<maxFlow()<<endl;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值