由题意知道问题需要统计一个信息,(Alice可以再某一天拍摄某一部电影)词条的个数。如果这个个数等于每部电影要求的总和就可以安排的开。可以想到需要把alice,电影,天,汇点都编号为节点,找出这个图的所有的流(也就是词条的个数),天的编号比较麻烦,需要使用周数转换。寻找网络流使用朴素的增光路径算法。
#include<iostream>
#define IN 9
#define MAX 380
#define END 379
#define DAY 7
#define WEEK 8
using namespace std;
const int bigint = 99999;
int q[MAX],qs,qe,path[MAX],forward[MAX];
int s,e,t,n,d,w,total;
int a[IN];
int flow[MAX][MAX],capa[MAX][MAX];
int adj[MAX],edge[MAX][MAX];
bool findpath(){
int u,v;int i;
qs = 0; qe = 1;
q[0] = s;
for(i=0;i<MAX;i++) path[i] = bigint;
memset(forward,0,sizeof(int)*MAX);
while(qs < qe){
u = q[qs++];
for(i=1;i<=adj[u];i++){
v = edge[u][i];
if(path[v] == bigint){
if(flow[u][v] < capa[u][v] || flow[v][u] > 0){
q[qe++] = v;
path[v] = u;
if(flow[u][v] < capa[u][v])
forward[v] = 1;
}
}
}
}
return path[e] != bigint;
}
void modify_flow(){
int i=e,j=path[i];
while(j!=s){
if(forward[i]) flow[j][i]++;
else flow[i][j]--;
i = j;
j = path[i];
}
if(forward[i]) flow[j][i]++;
else flow[i][j]--;
}
void slove(){
int res = 0;
while(findpath()){
res++;
modify_flow();
}
if(res == total) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
void add_edge(int u,int v,int f){
capa[u][v] = f;
flow[u][v] = 0;
adj[u]++;
edge[u][adj[u]] = v;
adj[v]++;
edge[v][adj[v]] = u;
}
void init(){
s = 0;e = END;total = 0;
memset(flow,0,sizeof(int)*MAX*MAX);
memset(capa,0,sizeof(int)*MAX*MAX);
memset(edge,0,sizeof(int)*MAX*MAX);
memset(adj,0,sizeof(int)*MAX);
}
int main(){
int i,j,k;
cin >> t;
while(t-->0){
init();
cin >> d;
for(j=0;j<d;j++){
for(i=0;i<9;i++){
cin >> a[i];
}
total += a[DAY];
add_edge(s,j+1,a[DAY]);
for(i=0;i<7;i++){
if(a[i]){
for(k=0;k<a[WEEK];k++){
add_edge(j+1,d+7*k+i+1,1);
add_edge(d+7*k+i+1,e,1);
}
}
}
}
slove();
}
}