poj 1698 最大流

额。。很难得自己终于会构图了。。但是构了个费用流。。。一会看看能不能过。。

题意:

    n个电影需要演,每个电影都有特定的日期可以拍摄,每个电影也都要在特定的星期数里完成,而且也有其必须要演的天数。小Alice同时做它们,问能不能最后都完成他们(周数做多的那个完成时,所有的电影都完成了)。

题解:

    每个电影都建点,每天都建点(建max周数 *7个点),源点到每个电影点建边 c为这个电影所要演的天数。每个电影对他能演的天数建边,c=1。每天对汇点建边,c=1。这样最大流过后如果流量等于总天数,那么Yes,否则No。


#include<stdio.h>
#include<string.h>
#define nMax 100000
#define MX 100000000
int que[nMax*5],n,T,list[nMax],dist[nMax],vs,vt,cas,k;
struct Egde{  
	int u,v,f,next;  
}eg[1000000];  
void add(int u,int v,int f){  
	eg[k].u=u;eg[k].v=v;eg[k].next=list[u];eg[k].f=f;list[u]=k++;  
	eg[k].u=v;eg[k].v=u;eg[k].next=list[v];eg[k].f=0;list[v]=k++;  
}
int dinic(int s,int t){  
	int ans=0;  
	while(true){  
		int head,tail,id,i;  
		head=tail=0;  
		que[tail++]=s;  
		memset(dist,-1,sizeof(dist));  
		dist[s]=0;  
		while(head<tail){  
			id=list[que[head++]];  
			while(id!=-1){  
				if(eg[id].f>0&&dist[eg[id].v]==-1){  
					dist[eg[id].v]=dist[eg[id].u]+1;  
					que[tail++]=eg[id].v;  
					if(eg[id].v==t){  
						head=tail;  
						break;  
					}  
				}  
				id=eg[id].next;  
			}  
		}  
		if(dist[t]==-1)  
			break;  
		id=s,tail=0;  
		while(true){  
			if(id==t){  
				int flow=MX,fir;  
				for(i=0;i<tail;i++)  
					if(eg[que[i]].f<flow){  
						fir=i;  
						flow=eg[que[i]].f;  
					}  
				for(i=0;i<tail;i++)  
					eg[que[i]].f-=flow,eg[que[i]^1].f+=flow;  
				ans+=flow;  
				tail=fir;  
				id=eg[que[fir]].u;  
			}  
			id=list[id];  
			while(id!=-1){  
				if(eg[id].f>0&&dist[eg[id].u]+1==dist[eg[id].v])  
					break;  
				id=eg[id].next;  
			}  
			if(id!=-1){  
				que[tail++]=id;  
				id=eg[id].v;  
			}  
			else{  
				if(tail==0)  
					break;  
				dist[eg[que[tail-1]].v]=-1;  
				id=eg[que[--tail]].u;  
			}  
		}  
	}  
	return ans;  
}
struct Week{
		int f[7],d,w;
}week[30];
int main(){
	scanf("%d",&T);
	while(T--){
		memset(list,-1,sizeof(list));
		scanf("%d",&n);
		int D=0;
		int maxw=0;
		for(int i=0;i<n;i++){
			for(int j=0;j<7;j++){
				scanf("%d",&week[i].f[j]);
			}
			scanf("%d",&week[i].d);
			D+=week[i].d;
			scanf("%d",&week[i].w);
			if(week[i].w>maxw){
				maxw=week[i].w;
			}
		}
		vs=0;vt=n+maxw*7+1;
		for(int i=1;i<=n;i++){
			add(vs,i,week[i-1].d);
		}
		for(int i=0;i<n;i++){
			for(int k=0;k<week[i].w;k++){
				for(int j=0;j<7;j++){
					if(week[i].f[j]){
						add(i+1,j+1+n+k*7,1);
					}
				}
			}
		}
		for(int i=n+1;i<=n+maxw*7;i++){
			add(i,vt,1);
		}
		int ans=dinic(vs,vt);
		if(D==ans){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值