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;
}