POJ 1698 Alice's Chance 【网络流-构图】

89 篇文章 0 订阅
16 篇文章 0 订阅

网络流构图题目,构图方式:

每部电影与源之间连边,权值为本电影拍摄需要的天数。将所有的天数都抽象成点(最多为50*7),将每部电影与可行的日子之间连接一条边,权值为1,然后将所有的日子与汇点连接一条边,权值为1.


在这个图上面跑最大流,流经每个电影的最大流量为规定的天数,而且,如果从某个电影出发的流流经了某天的话,将不会有其它流流经——因为每一天与汇点之间的权值为1,即最多有一个电影的流可以通过该天流到汇点。


因此,只需要判断最大流是否等于所有电影要求的天数之和即可判断可行性。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define N 400
#define INF 0x3f3f3f3f
struct Dinic {
    int c[N][N], n, s, t, l[N], e[N];
    int flow(int maxf = INF) {
        int left = maxf;
        while (build()) left -= push(s, left);
        return maxf - left;
    }
    int push(int x, int f) {
        if (x == t) return f;
        int &y = e[x], sum = f;
        for (; y<n; y++)
            if (c[x][y] > 0 && l[x]+1==l[y]) {
                int cnt = push(y, min(sum, c[x][y]));
                c[x][y] -= cnt;
                c[y][x] += cnt;
                sum -= cnt;
                if (!sum) return f;
            }
        return f-sum;
    }
    bool build() {
        int m = 0;
        memset(l, -1, sizeof(l));
        l[e[m++]=s] = 0;
        for (int i=0; i<m; i++) for (int y=0; y<n; y++)
            if (c[e[i]][y] > 0 && l[y]<0) l[e[m++]=y] = l[e[i]] + 1;
        memset(e, 0, sizeof(e));
        return l[t] >= 0;
    }
} net;

int main() {
    int T, n, f[8], w, d, mw, ds;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        memset(net.c, 0, sizeof(net.c));
        ds = mw = 0;
        for (int i=0; i<n; i++) {
            for (int j=0; j<7; j++) scanf("%d", &f[j]);
            scanf("%d%d", &d, &w);
            ds += d;
            mw = max(w, mw);
            net.c[0][i+1] = d;
            for (int j=0; j<w; j++)
                for (int k=0; k<7; k++)
                    if (f[k]) net.c[i+1][8+j*7+k] = 1;
        }
        mw = 7*mw + 7;
        for (int j=8; j<=mw; j++) net.c[j][mw+1] = 1;
        net.t = mw + 1, net.n = mw + 2;
        if (ds == net.flow()) puts("Yes");
        else puts("No");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值