luogu P2754 [CTSC1999]家园(加边最大流)

luogu P2754 [CTSC1999]家园(加边最大流)

题目大意

由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。

现有 n 个太空站位于地球与月球之间,且有 m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船 i 只可容纳 H[i]个人。每艘太空船将周期性地停靠一系列的太空站,例如:(1,3,4)表示该太空船将周期性地停靠太空站 134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为 1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。

初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。

对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。

解题思路

对不同时间的不同空间站建不同的点,随着时间的增加不断地增加新的时刻的空间站,并让其与上个时刻,飞船驶过的空间站连边,并让相同空间站的不同时刻从前向后连容量无限的边,代表已经到了这个空间站的人可以在此空间站等待,设一个源点连向所有时刻的地球,建一个汇点被所有的月球连向,从源点向汇点跑最大流,当总的流量大于人数时则是将所有人运出的最小时间.可以发现对于一定的人数和站点数,天数将总有一个上界,当大于这个上界的时候将代表地月之间没有通路.

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
const int maxm=1e6+5;
const int inf=0x3f3f3f3f;
struct Edge{
	int to,nxt,cap,flow;
}edge[maxm];
int tol;
int head[maxn];
void init(){
	tol=2;
	memset(head,-1,sizeof(head));
}
void AddEdge(int u,int v,int w,int rw=0){
	edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;
	edge[tol].nxt=head[u];head[u]=tol++;
	edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0;
	edge[tol].nxt=head[v];head[v]=tol++;
}
int Q[maxn];
int dep[maxn],cur[maxn],sta[maxn];
bool bfs(int s,int t,int n){
	int front=0,tail=0;
	memset(dep,-1,sizeof(dep[0])*(n+1));
	dep[s]=0;
	Q[tail++]=s;
	while(front<tail){
		int u=Q[front++];
		for(int i=head[u];i!=-1;i=edge[i].nxt){
			int v=edge[i].to;
			if(edge[i].cap>edge[i].flow&&dep[v]==-1){
				dep[v]=dep[u]+1;
				if(v==t) return true;
				Q[tail++]=v;
			}
		}
	}
	return false;
}
int dinic(int s,int t,int n){
	int maxflow=0;
	while(bfs(s,t,n)){
		for(int i=0;i<n;i++) cur[i]=head[i];
		int u=s,tail=0;
		while(cur[s]!=-1){
			if(u==t){
				int tp=inf;
				for(int i=tail-1;i>=0;i--)
				{
					tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
				}
				maxflow+=tp;
				for(int i=tail-1;i>=0;i--){
					edge[sta[i]].flow+=tp;
					edge[sta[i]^1].flow-=tp;
					if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i;
				}
				u=edge[sta[tail]^1].to;
			}
			else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){
				sta[tail++]=cur[u];
				u=edge[cur[u]].to;
			}
			else{
				while(u!=s&&cur[u]==-1) u=edge[sta[--tail]^1].to;
				cur[u] = edge [cur[u]].nxt;
			}
		}
	}
	return maxflow;
}
int h[25],c[25][20];
int main()
{
	init();
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	int x;
	n+=2;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&h[i],&c[i][0]);
		for(int j=1;j<=c[i][0];j++) {scanf("%d",&c[i][j]);c[i][j]++;};
	}
	int day=1;
	bool flag=0;
	int days,nday;
	int humans=0;
	while(day<=500)
	{
		AddEdge(0,day*n+1,inf);
		AddEdge(day*n,1e4,inf);
		for(int i=0;i<n;i++) AddEdge(day*n+i,(day+1)*n+i,inf);
		for(int i=1;i<=m;i++)
		{
			days=day%c[i][0]+(day%c[i][0]==0)*c[i][0];
			nday=((day+1)%c[i][0])+((day+1)%c[i][0]==0)*c[i][0];
			AddEdge(day*n+c[i][days],(day+1)*n+c[i][nday],h[i]);
		}
		humans+=dinic(0,1e4,1e4);
		if(humans>=k) {flag=1;break;}
		day++;
	}
	if(flag==0) cout<<0<<endl;
	else cout<<day-1<<endl;
}

猜你喜欢

转载自blog.csdn.net/baiyifeifei/article/details/87939094