题意:Alice要参演电影,但同时有几个电影,Alice想都参演,问能否都能演上;输入T个样例,每个样例有n个电影,然后输入一星期的哪几天可以演这个电影,然后是电影需要d天,要在w星期内完成;
题解:最大流问题,添加源点s=0,汇点t=399,对于编号从1……n编号,将源点和电影i相连,容量置为该部电影拍摄完成需要的天数,将电影i和其特定的拍摄日期相连(将第k星期的星期j编号为n+7*k+j),该边的容量置为1,然后将该日期和汇点相连,容量也是置为1,再对构建的网络求解最大流,如果该最大流等于所有电影拍摄完成需要的天数,那么输出"Yes",否则输出"No".
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define maxn 400
#define INF 0xffffff
int cap[maxn][maxn],flow[maxn][maxn],res[maxn],pre[maxn];
int n,d[25],w[25],f[25][10];
int Edmonds_Karp(int start,int end)
{
int maxflow=0;
memset(flow,0,sizeof(flow));
memset(pre,0,sizeof(pre));
queue<int> q;
while(true)
{
memset(res,0,sizeof(res));
res[start]=INF;
q.push(start);
while(!q.empty()) //BFS寻找增广路
{
int u=q.front();
q.pop();
for(int v=1;v<=end;v++)
if(!res[v]&&cap[u][v]>flow[u][v])
{
res[v]=min(res[u],cap[u][v]-flow[u][v]);//start-v路径上的最小残量
//记录v的父亲,并加入队列中
pre[v]=u;
q.push(v);
}
}
if(res[end]==0) return maxflow;//无法继续更新最大流量,则当前流已经是最大流
for(int u=end;u!=start;u=pre[u])//从汇点往回走
{
flow[pre[u]][u]+=res[end];//更新正向流
flow[u][pre[u]]-=res[end];//更新反向流
}
maxflow+=res[end]; //更新从s流出的总流量
}
return maxflow;
}
int main()
{
int test;
scanf("%d",&test);
while(test--)
{
memset(cap,0,sizeof(cap));
int sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=7;j++)
{
scanf("%d",&f[i][j]);
}
scanf("%d%d",&d[i],&w[i]);
sum+=d[i];
}
for(int i=1;i<=n;i++)
{
cap[0][i]=d[i];
}
for(int i=21;i<=398;i++)
{
cap[i][399]=1;
}
for(int i=1;i<=n;i++)
{
for(int k=0;k<w[i];k++)
{
for(int j=1;j<=7;j++)
{
cap[i][20+k*7+j]=f[i][j];
}
}
}
if(sum==Edmonds_Karp(0,399))
printf("Yes\n");
else printf("No\n");
}
return 0;
}