题意: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;
}