题目大意:爱丽丝要拍电影,有n部电影,规定爱丽丝每部电影在每个礼拜只有固定的几天可以拍电影,只可以拍前面w个礼拜,并且这部电影要拍d天,问爱丽丝能不能拍完所有的电影
第一行代表有多少组数据
对于每组数据第一行代表有n部电影
接下来2到n+1行,每行代表一个电影,每行9个数,前面7个数,1代表拍,0代表不拍,第8个数代表要拍几天,第9个数代表有几个礼拜时间拍
解题思路:
这题可以看做成二分图多重匹配,也可以用网络流实现,主要是建图,将图建好了就好说了
用s=0表示源点,t=371表示汇点....
1-20表示电影,因为电影最多只有20部
将371看做汇点的原因是,21-370表示每天,因为最多有50个星期
源点指向每部电影,最大容量为这部电影所拍摄的天数
电影指向天数,因为每天只能拍一部电影,若这天可以拍这部电影就表示最大容量为1
天数都指向汇点,最大容量都为1
这样建好图之后就可以直接从源点到汇点求最大流,看最大流是否等于每个电影天数相加只和,相等则可以拍完,不等则拍不完
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <queue>
using namespace std;
#define inf 0x7ffffff
#define N 500
#define M 20000
int dis[N], cur[N],gap[N],head[N],pre[N];
int nv,ne,s,t,top,max_week,sum;
struct node
{
int u,v,c,next;
}edge[M];
void init()
{
top = 0;
memset(head,-1,sizeof(head));
s = 0; // start position
max_week = -1;
sum = 0;
}
void add_edge(int u,int v, int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
int sap()
{
int flow=0,max_flow=inf,u,v;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for(int i=0; i<nv; i++) cur[i]=head[i];
gap[s]=nv;
u=pre[s]=s;
while(dis[s]<nv)
{
loop :
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
v=edge[j].v;
if(edge[j].c>0&&dis[u]==dis[v]+1)
{
if(edge[j].c<max_flow) max_flow=edge[j].c;
pre[v]=u;
u=v;
if(v==t)
{
for(u=pre[v];v!=s;v=u,u=pre[u])
{
edge[cur[u]].c-=max_flow;
edge[cur[u]^1].c+=max_flow;
}
flow+=max_flow;
max_flow=inf;
}
goto loop ;
}
}
int mindis=nv;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
v=edge[j].v;
if(edge[j].c>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
int i,j,k,h,time,ans,n,work[7],day,week;
scanf("%d",&time);
while(time--)
{
init();
scanf("%d",&n);
for(i = 1; i <= n; ++i)
{
for(j = 0;j < 7; ++j)
scanf("%d",&work[j]);
scanf("%d%d",&day,&week);
add_edge(s,i,day); //源点到电影连边
for(j = 0;j < week; ++j)
for(k = 0;k < 7; ++k)
if(work[k]) // can do
add_edge(i,n+j*7+k+1,inf); //电影到固定的礼拜连边
max_week = max_week>week?max_week:week; //最多到几周
sum += day;
}
t = n+max_week*7+1;
nv = t + 1;
for(i = 0;i < max_week; ++i )
for(j = 1;j <= 7; ++j)
add_edge(n+i*7+j,t,1); //天数与汇点连边
ans = sap();
// printf("%d ",ans);
if(sum == ans)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}