【线性规划与网络流24题 13】星际转移
Time Limit:10000MS Memory Limit:65536K
Total Submit:15 Accepted:0
Case Time Limit:1000MS
Description
由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。现有n个太空站
位于地球与月球之间,且有m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船i 只可容纳H[i]个人。每艘太空船将周期性地停靠一系列的太空站,
例如:(1,3,4)表示该太空船将周期性地停靠太空站134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。
编程任务:
对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。
Input
第1行有3 个正整数n(太空站个数),m(太空船个数)和k(需要运送的地球上的人的个数)。其中 1<=m<=13, 1<=n<=20, 1<=k<=50。
接下来的m行给出太空船的信息。第i+1 行说明太空船pi。第1 个数表示pi 可容纳的人数Hpi;第2 个数表示pi 一个周期停靠的太空站个数r,1<=r<=n+2;随后r 个数是停靠的太空站的编号(Si1,Si2,…,Sir),地球用0 表示,月球用-1 表示。时刻0 时,所有太空船都
在初始站,然后开始运行。在时刻1,2,3…等正点时刻各艘太空船停靠相应的太空站。人只有在0,1,2…等正点时刻才能上下太空船。
Output
程序运行结束时,将全部人员安全转移所需的时间输出。如果问题无解,则输出0。
Sample Input
2 2 1
1 3 0 1 2
1 3 1 2 –1
Sample Output
5
Source
感谢 Wo_ai_WangYuan 放上数据
无解很好判断,一个dfs就可以搞定
接下来我们考虑构图
方便起见,我们把每一个太空站(包括地球月球)的编号加上一个3,源点为0,汇点为1
首先开始的时候,我们将源点和地球连上一条容量为inf的边,月球和汇点连上一条容量为inf的边
然后顺序枚举天数,对于第t天,将源点和<earth,t>连上一条容量inf的边,将<moon,t>和汇点连上一条容量为inf的边
然后对于每一个太空船,如果它在第t-1天到达太空站a,在第t天到达太空站b,那么将<a,t-1>,<b,t>连上一条容量为该太空船的最大容量的边
对于每一个太空站i,由于可以延时转移且容量无限大,将<i,t-1>和<i,t>连上一条容量为Inf的边
然后就求最大流,记住每一次求最大流都是在上一次求完之后的残量网络上进行的
用sum来记录当前求出的所有的最大流的和,如果sum>=k就说明所有人都从地球转移到月球了,输出此时的t
用sap要超时,所以用了刘汝佳提供的isap代码,怕有重边所以用的邻接表
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define getid(xx,day) ((day)*(n+2)+(xx))
using namespace std;
const int maxn=1500,inf=1e9;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
int n,m,k,last[maxn],h[60],cnt[60];
int ck[60][60],tot,op,ed,sum,END[maxn],LAST[maxn<<2],NEXT[maxn<<2];
int dis[maxn],vd[maxn],earth=3,moon=2,cur;
bool vis[60];
struct wr{
int a,b,c,w,NEXT;
wr(int a,int b,int c,int NEXT):a(a),b(b),c(c),NEXT(NEXT){}
};
vector<wr>s;
void insert(int a,int b,int c){
s.push_back(wr(a,b,c,last[a]));
last[a]=s.size()-1;
s.push_back(wr(b,a,0,last[b]));
last[b]=s.size()-1;
}
void add(int x,int y){
END[++cur]=y; NEXT[cur]=LAST[x]; LAST[x]=cur;
END[++cur]=x; NEXT[cur]=LAST[y]; LAST[y]=cur;
return ;
}
bool find(int x){
vis[x]=1;
if(x==moon)return 1;
for(int i=LAST[x],y;i;i=NEXT[i])
if(!vis[END[i]]&&find(END[i]))return 1;
return 0;
}
int dfs(int x,int flow){
if(x==ed)return flow;
int delta=0,sud=0,mind=tot-1,i,y;
for(i=last[x];i>=0;i=s[i].NEXT)
if(s[i].c){
y=s[i].b;
if(dis[x]==dis[y]+1){
delta=min(s[i].c,flow-sud);
delta=dfs(y,delta);
s[i].c-=delta;
s[i^1].c+=delta;
sud+=delta;
if(dis[op]>=tot)return sud;
if(sud==flow)break;
}
mind=min(mind,dis[y]);
}
if(!sud){
--vd[dis[x]];
if(!vd[dis[x]])dis[op]=tot;
dis[x]=mind+1;;
++vd[dis[x]];
}
return sud;
}
void sap(){
memset(vd,0,sizeof(vd));
memset(dis,0,sizeof(dis));
vd[0]=tot;
while(dis[op]<tot)sum+=dfs(op,inf);
}
int main(){
_read(n);_read(m);_read(k);
int i,j,q,p,x,y,t=0;
for(i=1;i<=m;i++){
_read(h[i]);_read(cnt[i]);
for(j=0;j<cnt[i];j++){
_read(x);
ck[i][j]=x+3;
}
}
for(i=1;i<=m;i++)
for(j=0;j<cnt[i];j++)
add(ck[i][j],ck[i][(j+1==cnt[i])?(0):(j+1)]);
if(!find(earth)){
putchar('0');
return 0;
}
memset(last,-1,sizeof(last));
op=0,ed=1;
tot=n+4;
insert(op,getid(earth,0),inf);
insert(getid(moon,0),ed,inf);
while(sum<k){
t++,tot+=n+2;
insert(op,getid(earth,t),inf);
insert(getid(moon,t),ed,inf);
for(i=1;i<=m;i++){
int d1=ck[i][(t-1)%cnt[i]],d2=ck[i][t%cnt[i]];
insert(getid(d1,t-1),getid(d2,t),h[i]);
}
for(i=-1;i<=n;i++)
insert(getid(i+3,t-1),getid(i+3,t),inf);
sap();
}
cout<<t;
}
本文提出了一种解决星际转移问题的算法,通过建立网络流模型,在给定太空船信息的情况下,找到最快将人员全部转移到月球的方案。

被折叠的 条评论
为什么被折叠?



