POJ 3281 Dining (最大流)

题意:n头奶牛,f个食物,d个饮料,当一个食物或饮料被奶牛吃掉后,不能再被其他奶牛吃掉,每头奶牛都有喜欢的食物、饮料,求吃掉喜欢的食物和饮料的最多奶牛数量。

题解:最大流
要是只有食物,就可以用二分图匹配了。
这里用最大流的方式很巧妙,从源点->食物->奶牛->饮料->汇点,这样建边,最大流就是答案,但是奶牛只能吃一种食物或饮料,单单这样建边奶牛会吃掉其他的。
我们在食物和饮料之间再放一组奶牛,即源点->食物->奶牛->奶牛->饮料->汇点,这样也就避免了上述情况。

这里用sap求最大流,边的权值都是1,保证一一匹配。

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int n, f, d, fn, dn;
int cf, cd;
/*
 * SAP 邻接矩阵形式
 * 点的编号从 0 开始
 * 增加个 flow 数组,保留原矩阵 maze, 可用于多次使用最大流
 */
const int MAXN = 510;
int maze[MAXN][MAXN];
int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int flow[MAXN][MAXN];//存最大流的流量
int sap(int start, int end, int nodenum) {
    memset(cur, 0, sizeof(cur));
    memset(dis, 0, sizeof(dis));
    memset(gap, 0, sizeof(gap));
    memset(flow, 0, sizeof(flow));
    int u = pre[start] = start, maxflow = 0, aug = -1;
    gap[0] = nodenum;
    while (dis[start] < nodenum) {
    loop:
        for (int v = cur[u]; v < nodenum; v++)
            if (maze[u][v] - flow[u][v] && dis[u] == dis[v] + 1) {
                if (aug == -1 || aug > maze[u][v] - flow[u][v]) aug = maze[u][v] - flow[u][v];
                pre[v] = u;
                u = cur[u] = v;
                if (v == end) {
                    maxflow += aug;
                    for (u = pre[u]; v != start; v = u, u = pre[u]) {
                        flow[u][v] += aug;
                        flow[v][u] -= aug;
                    }
                    aug = -1;
                }
                goto loop;
            }
        int mindis = nodenum - 1;
        for (int v = 0; v < nodenum; v++)
            if (maze[u][v] - flow[u][v] && mindis > dis[v]) {
                cur[u] = v;
                mindis = dis[v];
            }
        if ((--gap[dis[u]]) == 0) break;
        gap[dis[u] = mindis + 1]++;
        u = pre[u];
    }
    return maxflow;
}
int main() {
	scanf("%d%d%d", &n, &f, &d);
    for (int i = 1; i <= f; i++) maze[0][i] = 1;
    for (int i = f + 2 * n + 1; i <= n * 2 + f + d; i++) maze[i][n * 2 + f + d + 1] = 1;
    for (int i = f + 1; i <= f + n; i++) maze[i][i + n] = 1;
	for (int i = 1; i <= n; i++) {
		scanf("%d%d", &fn, &dn);
        for (int j = 1; j <= fn; j++) {
            scanf("%d", &cf);
            maze[cf][i + f] = 1;
        }
        for (int j = 1; j <= dn; j++) {
            scanf("%d", &cd);
            maze[f + n + i][f + 2 * n + cd] = 1;
        }
	}
    printf("%d\n", sap(0, n * 2 + f + d + 1, n * 2 + f + d + 2));
	return 0;
}

你可能感兴趣的:(#,网络流)