POJ - 3481 Dining (拆点 + 最大流)

http://poj.org/problem?id=3281

题意:

农夫有n头牛,F种食物,D种饮料,每头牛都有各自喜欢的食物和饮料,问最多有几头牛吃到自己喜欢的东西

思路:

可以用最大流写,
一个超级源点S连接食物,一个超级汇点T连接饮料,食物与对应的牛连接,牛与对应的饮料连接。
但是得把牛的点拆开,因为牛只有一个,牛自身的流量为1,如果不把牛给拆开的话,会把最大流量算大
比如这样:
这里写图片描述
这样的话,最大流跑出来的是2,而牛只有一只,所以答案应该是1
因此把牛与牛之间建一条容量为1的边即可
像这样
这里写图片描述

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <string.h>
#include <queue>
#include <stack>
#include <deque>
#include <stdlib.h>
#include <bitset>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 105
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1e9 + 7

int N, F, D;
int mp[4 * maxn][4 * maxn], dis[4 * maxn];
int st = 1, en;

int bfs() {
    memset(dis, -1, sizeof(dis));
    dis[en] = 0;
    queue<int> que;
    que.push(en);
    while(!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = st; i <= en; i ++) {
            if(dis[i] == -1 && mp[i][u]) {
                dis[i] = dis[u] + 1;
                que.push(i);
            }
        }
    }
    return dis[st] != -1;
}

int dfs(int u, int flow) {
    int a = 0;
    if(u == en) return flow;
    for (int i = st; i <= en; i ++) {
        if(dis[u] == dis[i] + 1 && mp[u][i] && (a = dfs(i, min(flow, mp[u][i])))) {
            mp[u][i] -= a;
            mp[i][u] += a;
            return a;
        }
    }
    return 0;
}

int dinic() {
    int ans = 0;
    while(bfs())
        ans += dfs(1, INF);
    return ans ;
}

int main(int argc, const char * argv[]) {
    memset(mp, 0, sizeof(mp));
    scanf("%d %d %d", &N, &F, &D);
    en = 2 + 2 * N + F + D;
    for (int i = st + 1; i <= F + st; i ++) //源点到食物
        mp[st][i] = 1;

    for (int i = st + F + 2 * N + 1; i <= 1 + F + 2 * N + D; i ++) //饮料到汇点
        mp[i][en] = 1;

    for (int i = 1; i <= N; i ++) {
        mp[st + F + i][st + F + N + i] = 1;
        int f, d;
        scanf("%d %d", &f, &d);
        for (int j = 1, x; j <= f; j ++) {
            scanf("%d", &x);
            mp[st + x][i + F + st] = 1; //食物到牛
        }
        for (int j = 1, x; j <= d; j ++) {
            scanf("%d", &x);
            mp[i + F + N + st][st + x + F + 2 * N] = 1;//牛到饮料
        }
    }
    printf("%d\n", dinic());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81977745