您的位置:首页 > 其它

poj1698 - Alice's Chance (最大流)

2014-02-24 21:37 288 查看
题目大意:爱丽丝要拍电影,有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
, cur
,gap
,head
,pre
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: