【最大流】BAPC2014 A Avoiding the Apocalypse (Codeforces GYM 100526)

题目链接:

  http://codeforces.com/gym/100526

  http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11664&courseid=0

题目大意:

  总共N个点,现在有P个人,在T时间内要从起点S走到C个医疗站中的任意一个,M条X到Y的有向边,每条边每个单位时间可以通过的人数是pi,走完这条边耗时ti。

  人可以停留在任意一个点,求最多能有多少人到达医疗站。

  (1<=C<=N<=1000,0<=M<=1000,1<=P,T<=100,1<=pi,ti<=100)

题目思路:

  【最大流】

  SPFA居然T了。。

  将每个点按照时间拆点{X节点j时间的状态为点X(j)},把X到Y的边pi,ti拆成T-ti条边,每条边从X(j)到Y(j+ti)容量为pi,j为时间从0~T-ti,表示在j时间有pi个人可以从X到Y,到达Y的时间为j+ti。

  因为人可以停留在节点上所以X(i)到X(i+1)连一条容量P的边。

  每个医疗站的最终时间Ci(T)到超级汇T_T连一条容量为P的边(到达医疗站的人就无限停留直到时间为T到超级汇T_T)

  超级源S_S到起点S(0)连一条容量为P的边表示初始起点S有P个人。

  最终统计到达超级汇的人数即可。跑一遍最大流。



//
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-8)
#define J 10
#define mod 1000000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#define N 1004
#define M 104
using namespace std;
typedef long long LL;
int cas,cass;
int n,m,lll,ans;
int s,p,t,S,T,nn;
int c[N];
int last[N*M+M],vd[N*M+M],d[N*M+M];
struct xxx
{
	int next,to,q;
}a[N*M*M];
void add(int x,int y,int f)
{
	a[++lll].next=last[x];
	a[lll].to=y;
	a[lll].q=f;
	last[x]=lll;
}
int sap(int u,int f)
{
	int i,v,tt,asp=0,mix=nn-1;
	if(u==T)return f;
	for(i=last[u];i;i=a[i].next)
	{
		v=a[i].to;
		if(a[i].q>0)
		{
			if(d[u]==d[v]+1)
			{
				tt=sap(v,min(f-asp,a[i].q));
				asp+=tt;
				a[i].q-=tt;
				a[i^1].q+=tt;
				if(asp==f || d[S]==nn)
					return asp;
			}
			mix=min(mix,d[v]);
		}
	}
	if(asp!=0)return asp;
	if(!--vd[d[u]])d[S]=nn;
	else vd[d[u]=mix+1]++;
	return asp;
}
int main()
{
	#ifndef ONLINE_JUDGE
//	freopen("1.txt","r",stdin);
//	freopen("2.txt","w",stdout);
	#endif
	int i,j,k;
	int x,y,f,dd;
//	for(scanf("%d",&cas);cas;cas--)
//	for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
//	while(~scanf("%s",s+1))
//	while(~scanf("%d",&n))
	{
		ans=0;lll=1;mem(vd,0);mem(d,0);mem(last,0);
		scanf("%d%d%d%d%d",&n,&s,&p,&t,&cass);
		S=n*t+t+1;T=S+1;
		nn=T;vd[0]=nn-t+1;
		add(S,t,p);
		add(t,S,0);
		add(t,s*t+1,p);
		add(s*t+1,t,0);
		for(i=1;i<=n;i++)
		{
			for(j=1;j<t;j++)
			{
				add(i*t+j,i*t+j+1,p);
				add(i*t+j+1,i*t+j,0);
			}
		}
		for(i=1;i<=cass;i++)
		{
			scanf("%d",&c[i]);
			add(c[i]*t+t,T,p);
			add(T,c[i]*t+t,0);
		}
		scanf("%d",&m);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d%d",&x,&y,&f,&dd);
			for(j=1;j+dd<=t;j++)
			{
				add(x*t+j,y*t+j+dd,f);
				add(y*t+j+dd,x*t+j,0);
			}
			if(x==s)
			{
				add(t,y*t+dd,f);
				add(y*t+dd,t,0);
			}
		}
		while(d[S]<nn)
		{
			f=sap(S,MAX);
			ans+=f;
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
//

//
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值