网络流构图题目,构图方式:
每部电影与源之间连边,权值为本电影拍摄需要的天数。将所有的天数都抽象成点(最多为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;
}