POJ 1698 Alice's Chance(最大流,构图题)

今天早上还算顺利,过了两题不是很水的题目,这题Alice就是一个构图题,刚开始感觉思路是有的,可能交了一边是WA就郁闷了!刚开始的思路是

“ 把源点和周一到周日相连,权值是全部电影中需要的星期最长的,如第一个例题是4,
然后 日期1到7和电影从8开始有关的相连,权值是电影需要的星期数,最后是电影到汇点的权值是需要的天数。”

话说某大神要是看到这个思想,希望提出不足之处,非常感谢!

发现不行的,之后改成了把每个电影需要的星期数都拆开,变成一条线的权值设为1,这样每个星期中的某一天只能被一部电影占据,源点直接连接到电影,权值为需要的天数,之后将日期和汇点相连,比如有一部电影需要4周,就需要有4*7=28个点和汇点相连!这样开了15000的数据,还能32MS,Dinic挺快的了!

构图题,Dinic用的还是之前的模板!没什么好讲的了!

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define maxn 16000
const int INF=0xffffff;
int f[25][9];
struct edge
{
	int from,to,val,next;
}map[maxn];
int vis[maxn],que[maxn],dist[maxn],len;
void init()        //初始化  切记
{
	len=0;
	memset(vis,-1,sizeof(vis));
}
void insert (int from,int to,int val)
{
	map[len].from=from,map[len].to=to,map[len].val=val;
	map[len].next=vis[from];
	vis[from]=len++;
	map[len].from=to,map[len].to=from,map[len].val=0;
	map[len].next=vis[to];
	vis[to]=len++;
}
int Dinic(int n,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=vis[que[head++]];
			while(id!=-1)
			{
				if(map[id].val>0&&dist[map[id].to]==-1)
				{
					dist[map[id].to]=dist[map[id].from]+1;
					que[tail++]=map[id].to;
					if(map[id].to==t)
					{
						head=tail;
						break;
					}
				}
				id=map[id].next;
			}
		}
		if(dist[t]==-1)
			break;
		id=s,tail=0;
		while(true)
		{
			if(id==t)       //找到一条增广路
			{
				int flow=INF,fir;
				for(i=0;i<tail;i++)
					if(map[que[i]].val<flow)
					{
						fir=i;
						flow=map[que[i]].val;
					}
					for(i=0;i<tail;i++)
						map[que[i]].val-=flow,map[que[i]^1].val+=flow;
					ans+=flow;
					tail=fir;
					id=map[que[fir]].from;
			}
			id=vis[id];
			while(id!=-1)
			{
				if(map[id].val>0&&dist[map[id].from]+1==dist[map[id].to])
					break;
				id=map[id].next;
			}
			if(id!=-1)
			{
				que[tail++]=id;
				id=map[id].to;
			}
			else
			{
				if(tail==0)
					break;
				dist[map[que[tail-1]].to]=-1;
				id=map[que[--tail]].from;
			}
		}
	}
	return ans;
}          //以上是纯模板   只要知道输入 Dinic  的三个int  是点数 起点  汇点 
int main()
{
    int n,i,j;
	int t;
	int sum;	
	int D,W,k;
	int flag=0;
	scanf("%d",&t);
	while(t--)
	{
		memset(f,0,sizeof(f));
		init();
		flag=0;
		sum=0;
		scanf("%d",&n);
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=7;j++)
				scanf("%d",&f[i][j]);
			scanf("%d%d",&D,&W);
		insert(0,i,D);    //源点和电影部数相连
		sum+=D;		
			if(flag<W)
				flag=W;
		for(k=0;k<W;k++)
			for(j=1;j<=7;j++)
				if(f[i][j])
					insert(i,7*k+j+n,1);        //电影和各周中相应的天数相连,权值为1
		}
		int T=n+7*flag+1;
		for(i=0;i<flag;i++)         //将每个星期的周一到周日都和汇点相连
			for(j=1;j<=7;j++)
			insert(7*i+n+j,T,1);
		int ans=Dinic(T+1,0,T);
		if(sum==ans)        //如果需要的天数满流就YES
			printf("Yes\n");
		else
			printf("No\n");
		
	}
	return 0;
}

我把代码折起来是希望看到思路的人自己回去敲一下!这样进步比较快!

posted @ 2011-08-17 10:29  Lxsec  阅读(842)  评论(0编辑  收藏  举报