pku1149

一道最大流的题目,题意大概是:某某人有m个猪圈,有n个顾客,顾客要买猪,每个顾客手头有若干个猪圈的钥匙,每个顾客只能买他有钥匙的那个猪圈的猪,顾客买猪有先后顺序,问能卖出最多多少猪。

主要是建图,当当前顾客能打开的猪圈在以后某个顾客也能打开时,在当前顾客和那个顾客之间连一条边,权值为无穷大。

/*
 * File:   pku1149.cpp
 * Author: chenjiang
 *
 * Created on 2010年3月24日, 下午12:31
 */

#include <stdlib.h>
#include <queue>
#include <iostream>
using namespace std;
#define inf 2147483
#define Max_V 120
int mapmap[Max_V][Max_V], min_flow[Max_V], flow[Max_V][Max_V];
int n, m, V, source, sink, pig[1005], house[1005], pre[Max_V];
int link[1005][105];

int MIN(int a, int b) {
    return a < b ? a : b;
}

int max_flow() {
    int i, j, k;
    memset(flow, 0, sizeof (flow));
    int ans = 0;
    while (1) {
        queue<int> Q;
        Q.push(source);
        memset(pre, -1, sizeof (pre));
        min_flow[source] = inf;
        pre[source] = -2;
        while (!Q.empty()) {
            int temp = Q.front();
            Q.pop();
            for (i = 0; i <= sink; i++) {
                if (pre[i] == -1 && flow[temp][i] < mapmap[temp][i]) {
                    Q.push(i);
                    pre[i] = temp;
                    min_flow[i] = MIN(min_flow[temp], (mapmap[temp][i] - flow[temp][i]));
                }
            }
            if (pre[sink] != -1) {
                k = sink;
                while (pre[k] >= 0) {
                    flow[pre[k]][k] += min_flow[sink];
                    flow[k][pre[k]] = -flow[pre[k]][k];
                    k = pre[k];
                }
                break;
            }
        }
        if (pre[sink] == -1)return ans;
        else ans += min_flow[sink];
    }
}

/*
 *
 */
int main(int argc, char** argv) {

    int i, j, k, A, B, t;
    while (cin >> m >> n) {
        memset(mapmap, 0, sizeof (mapmap));
        memset(link, 0, sizeof (link));
        source = 0;
        sink = n + 1;
        for (i = 1; i <= m; i++) {
            cin >> pig[i]; //每个猪圈里猪的个数
        }
        for (i = 1; i <= n; i++) {//顾客
            cin >> A; //输入当前顾客能打开的猪圈个数
            for (j = 1; j <= A; j++) {//能打开的猪圈
                cin >> house[j]; //输入当前顾客能打开的猪圈
                bool flag = 0;
                for (t = 1; t < i; t++) {//
                    if (link[house[j]][t] != 0) {//如果house[j]与t有一条边
                        mapmap[t][i] = inf; //顾客t和i有一条无限大的边
                        flag = 1;
                    }
                }
                if (flag == 0) {//如果house[j]和i前面的顾客都没有联系,则与i连接
                    mapmap[source][i]+=pig[house[j]];
                    link[house[j]][i]=pig[house[j]];
                }
            }
            cin >> B;
            for (j = 1; j <= A; j++) {
                mapmap[i][sink] = B;//顾客和汇点连接
            }
        }/*
        for (i = 0; i <= sink; i++) {
            for (j = i + 1; j <= sink; j++) {
                printf("mapmap[%d][%d]=%d/n", i, j, mapmap[i][j]);
            }
        }
        system("pause");*/
        cout << max_flow() << endl;
    }
    return (EXIT_SUCCESS);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值