POJ 1698 Alice's chance 网络流最大流的题目,但是主要是考建图,图建出来后就套模板就行

说一下题意:有一个小女孩从小就梦想成为一名影星,现在机会来了,有很多电影公司找她拍电影,但是这些拍电影的日程安排之间可能还有冲突,但是女孩不想错过任何机会,想把每个公司的电影都接下来,但是她不知道能不能接下所有的电影,所以找到了你优秀的ACMER来帮忙解决问题。

数据的输入如下:有T组数据每组先有一个N表示要找她拍的电影的个数,其中N<=20;

每个电影有9个数据,前7个数据表示一个星期的7天 ,这7个数不是0,就是1,1表示能在这天拍电影,0表示不能在这天拍电影 还有2个数据D,W

D表示这部电影需要她拍D天才能完成,W表示这D天必须在前W周内。ok题意就是这样,下面考虑该怎样建图

***************************************

每部电影作为一个源点,然后把每个星期的每一天看成一个点,每个点只可以贡献一个工作日,即出边(到汇点)的容量只能是1,而入边的容量也为1,只要某部电影可以在该天工作,就可能选择该天,即该部电影对应的点到该个工作日对应的点之间连一条线,最后,添加一个超级源点,它到每部电影对于的点之间的容量为该部电影需要的工作日(不能为无穷大)

*****************************************

ok 图建完了就简单了只用判最大流是不是等于要拍的所有电影的天数的和,若等于就输出Yes,不然就输出No

ok细节部分见代码注释;若关于最大流的算法还不太了解可以看我的上一篇博客,关于最大流算法的介绍点击打开链接http://blog.csdn.net/hikean/article/details/9918093

这题我也是用的上一题的代码稍微改了一下,建图部分就出来了

代码如下:

/*********
PRO: POJ 1698
TIT: Alice's Chance
DAT: 2013-08-12
AUT: UKean
EMA: huyocan@163.com
*********/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define  INF 1e9
using namespace std;
queue<int> que;//广搜需要使用的队列
int M;//M是点数
int s,t;//源点和汇点
int flow[405][405];//流量
int p[405];//广搜记录路径的父节点数组
int a[405];//路径上的最小残量
int cap[405][405];//容量网络
int ans;//最大流
int data[30][10];//存读入数据的部分
int sum;//存拍所有电影需要的天数
int read()
{
	int flim_num;cin>>flim_num;
	for(int i=0;i<flim_num;i++)
		for(int j=0;j<9;j++)
		cin>>data[i][j];

	s=0;t=1;//源点汇点

	for(int i=M=0;i<flim_num;i++) M=max(data[i][8],M);
	M=M*7+30;//算出大概的总的点数

	memset(cap,0,sizeof(cap));
	//2 --21 是电影,22后面的点表示时间
	for(int i=2;i<flim_num+2;i++)
		cap[0][i]=data[i-2][7];//超级源点到每个电影的边
	//处理电影到每天
	for(int i=0;i<flim_num;i++)
		for(int j=0;j<7;j++)//j是一周的第几天
			if(data[i][j]==1)
			for(int k=0;k<data[i][8];k++)//k是第几周
			{
				cap[i+2][k*7+j+22]=1;//电影到第几天的边的容量
				cap[k*7+j+22][1]=1;//第几天到汇点的边的容量
			}
	sum=0;
	for(int i=0;i<flim_num;i++)
		sum+=data[i][7];//计算出拍完所有的电影需要的天数
	return 1;
}

int deal()//增广路算法
{
	memset(flow,0,sizeof(flow));
	ans=0;
	while(1)
	{
		memset(a,0,sizeof(a));
		a[s]=INF;
		que.push(s);
		while(!que.empty())
		{
			int u=que.front();que.pop();
			for(int v=1;v<=M;v++)
			if(!a[v]&&cap[u][v]-flow[u][v]>0)
			{
				p[v]=u;
				que.push(v);
				a[v]=min(a[u],cap[u][v]-flow[u][v]);//路径上的最小残流量
			}
		}
		if(a[t]==0) break;
		for(int u=t;u!=s;u=p[u])
		{
			flow[p[u]][u]+=a[t];
			flow[u][p[u]]-=a[t];
		}
		ans+=a[t];
	}
	//cout<<ans<<endl;
	return ans;
}
int main()
{
	int T;cin>>T;
	while(T--)
	{
		read();
		if(deal()==sum)
			puts("Yes");
		else
			puts("No");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值