poj 1149 PIGS【网络流经典建图】

题目链接

题意:
有n个顾客,有m个猪圈,每个猪圈有一定的猪,在开始的时候猪圈都是关闭的,顾客来买猪,顾客打开某个猪圈,可以在其中挑选一定的猪的数量,在这个顾客走后,可以在打开的猪圈中将某个猪圈的一些猪牵到另外一个打开的猪圈,然后所有的猪圈会关闭,这样下一个顾客来了继续上面的工作。

第一行是两个整数:m和n(1≤M≤1000,1≤N≤100)
m是猪圈的数目,n是顾客的数目
第二行是m个整数,为每个猪圈中初始猪的数目,范围是[0,1000]
第三行接下来有N行,每行第一个数A代表第几个顾客会依次打开A个猪圈,然后跟着有A个数,代表顾客打开的是哪个猪圈.最后有一个数代表这个顾客可以买多少只猪
现在求怎么一种方法,使所有顾客买的猪的总数最大.

思路:
源点 -》 顾客 -》 汇点 。(源点为0,顾客编号为1~n,汇点为n + 1)
第一步:
源点与顾客之间: 能够第一次进入i号猪圈的顾客与源点相连,流量为i号猪圈的猪数量。
第二步:
顾客与顾客之间:进入i号猪圈的第p位与第p + 1位连接,流量为无限大(因为与原点相连的那条流量做出了限制),随意支配猪的流动。
第三步:
顾客与汇点之间:每位顾客都可以与汇点相连,流量为该顾客需要的猪数量。

建图的题目类型

#include <cstdio>  
#include <cstring>   
#include <queue>  
#include <vector>
#include <algorithm>  
#define MAXN 2000+50
#define INF 0x3f3f3f
using namespace std;
int dist[MAXN], cur[MAXN], head[MAXN];
int pig[MAXN], need[MAXN], vis[MAXN];
int top;
vector<int> G[MAXN];

struct Edge {
    int to, cap, flow, next;
}edge[MAXN * 200];

void addedge(int a, int b, int c) {
//  int i; //处理重边,可以不用 
//  for(i = head[a]; i != -1; i = edge[i].next) {
//      if(edge[i].to == b) break;
//  }
//  if(i != -1) {
//      if(c != INF) edge[i].cap += c;
//      return;
//  }
    Edge E1 = {b, c, 0, head[a]};
    edge[top] = E1;
    head[a] = top++;
    Edge E2 = {a, 0, 0, head[b]};
    edge[top] = E2;
    head[b] = top++;
}

bool BFS(int start, int end) { 
    memset(dist, -1, sizeof(dist));  
    memset(vis, 0, sizeof(vis));  
    queue<int> Q; 
    Q.push(start);
    vis[start] = 1;
    dist[start] = 0; 
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next) {
            Edge E = edge[i];
            if(!vis[E.to] && E.cap > E.flow) {
                dist[E.to] = dist[u] + 1;
                vis[E.to] = 1;
                if(E.to == end) return true;
                Q.push(E.to);
            }
        }
    }
    return false;
}

int DFS(int x, int cost, int end) { 
    if(x == end || cost == 0) return cost;
    int flow = 0, f;
    for(int& i = cur[x]; i != -1; i = edge[i].next) {
        Edge& E = edge[i];
        if(dist[E.to] == dist[x] + 1 &&  (f = DFS(E.to, min(cost, E.cap - E.flow), end)) > 0) { 
            E.flow += f;
            edge[i ^ 1].flow -= f;
            flow += f;
            cost -= f;
            if(cost == 0) break;
        }
    }
    return flow;
}

int Maxflow(int start, int end) {
    int flow = 0;
    while(BFS(start, end)) { 
        memcpy(cur, head, sizeof(head));
        flow += DFS(start, INF, end);
    }
    return flow;
}

int t, k, n, m;
void getmap() { //核心部分 
    for(int i = 1; i <= m; i++) {
        scanf("%d", &pig[i]);
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &k);
            G[k].push_back(i); //猪圈和顾客相连接 
        }
        scanf("%d", &need[i]); //顾客需要的猪 
    }
    for(int i = 1; i <= m; i++) {
        int u = G[i][0]; //和源点链接 
        addedge(0, u, pig[i]);
        for(int j = 0; j < G[i].size() - 1; j++) { //别忘了减一 
            int x = G[i][j];
            int y = G[i][j + 1];
            addedge(x, y, INF);  //前后来到i号猪圈的顾客之间流无限大 
        }
    }
    for(int i = 1; i <= n; i++) {
        addedge(i, n + 1, need[i]);
    }
}

int main() {
    while(scanf("%d %d", &m, &n) != EOF) {
        top = 0;
        memset(head, -1, sizeof(head));
        memset(edge, 0, sizeof(edge));
        memset(G, 0, sizeof(G));
        getmap();
        printf("%d\n", Maxflow(0, n + 1));
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值