2431 星际转移问题
Time Limit : 1000 MS | Memory Limit : 65536 KB
Submits : 101 | Solved : 7
Description
由于人类对自然资源的消耗,人们意识到大约在2300年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。现有n个太空站位于地球与月球之间,且有m艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船i 只可容纳H[i]个人。每艘太空船将周期性地停靠一系列的太空站,例如:(1,3,4)表示该太空船将周期性地停靠太空站134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。要求对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。
Input
第1行有3个正整数n(太空站个数),m(太空船个数)和k(需要运送的地球上的人的个数)。其中 1<=m<=20, 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
分析:
可二分枚举最小时间,判断能否全部运输完。
S=0,代表超级源点;t=1,代表超级汇点(月球);2代表地球,二分枚举最大单位时间(tmp),将每个太空站拆为tmp个点,具体建图如下:
1. 从源点s向地球(2)建容量为K的边
2. 对于第i个太空站,从它第j-1单位时间代表的点向第j单位时间代表的点建一条容量为INF的边
3. 对于第i个太空船,假如第j-1单位时间停留在编号a的太空站,第j单位时间停留在编号b的太空站,则从a向b建一条容量为H[i]的边
建好图后,求出最大流,若等于k,说明可以运输完,继续枚举比tmp小的;若小于k,说明不能运输完,继续枚举比tmp大的。。。
这里还需注意的是:开始需特判能否到达月球,若不能,直接输出0;否则,按上述求。
dinic
#include<cstdio>
#include<cstring>
const int N=25000;
const int M=100000;
const int INF=0x7fffffff;
int tol,n,s,t,ans;
int head[N],d[N];
struct node
{
int y,f,nxt;
}edge[M];
int min(int a,int b){return a<b?a:b;}
void add(int x,int y,int f)
{
edge[tol].y=y;
edge[tol].f=f;
edge[tol].nxt=head[x];
head[x]=tol++;
edge[tol].y=x;
edge[tol].f=0;
edge[tol].nxt=head[y];
head[y]=tol++;
}
bool bfs()
{
int front=0,rear=0,q[N],u,v,i;
memset(d,-1,sizeof(d));
d[s]=0;
q[rear++]=s;
while(front<rear)
{
u=q[front++];
for(i=head[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].y;
if(edge[i].f&&d[v]==-1)
{
d[v]=d[u]+1;
if(v==t)return 1;
q[rear++]=v;
}
}
}
return 0;
}
int dfs(int s,int limit)
{
if(s==t)return limit;
int i,v,tmp,sum=0;
for(i=head[s];i!=-1;i=edge[i].nxt)
{
v=edge[i].y;
if(edge[i].f&&d[s]+1==d[v])
{
tmp=dfs(v,min(limit-sum,edge[i].f));
edge[i].f-=tmp;
edge[i^1].f+=tmp;
sum+=tmp;
if(limit==sum)return sum;
}
}
if(sum==0)d[s]=-1;
return sum;
}
void dinic(){while(bfs())ans+=dfs(s,INF);}
const int X=25;
int H[X],R[X],sr[X][X],sn,m,k;
bool No()
{
int i,j,x;
bool mm[X][X];
memset(mm,0,sizeof(mm));
for(x=1;x<=m;x++){
for(i=1;i<R[x];i++)for(j=0;j<i;j++){
mm[sr[x][i]][sr[x][j]]=1;
mm[sr[x][j]][sr[x][i]]=1;
}
}
int front=0,rear=0,q[X],u;
bool v[X];
memset(v,0,sizeof(v));
q[rear++]=2;v[2]=1;
while(front<rear)
{
u=q[front++];
for(i=1;i<=sn+2;i++)
{
if(mm[u][i]&&!v[i])
{
v[i]=1;
if(i==1)return 0;
q[rear++]=i;
}
}
}
return 1;
}
bool cal(int tmp)
{
int i,j,a,b;
ans=0,tol=0;
memset(head,-1,sizeof(head));
add(s,2,k);
for(i=3;i<=sn+2;i++)for(j=1;j<=tmp;j++)add(i+(j-1)*sn,i+j*sn,INF);
for(i=1;i<=m;i++)for(j=1;j<=tmp;j++)
{
a=sr[i][(j-1)%R[i]];
if(a>2)a+=(j-1)*sn;
b=sr[i][j%R[i]];
if(b>2)b+=j*sn;
add(a,b,H[i]);
}
dinic();
return ans==k;
}
int bsh()
{
int l=0,r=1080,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(cal(mid))r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
int i,j;
while(~scanf("%d%d%d",&sn,&m,&k))
{
for(i=1;i<=m;i++)
{
scanf("%d%d",&H[i],&R[i]);
for(j=0;j<R[i];j++)
{
scanf("%d",&sr[i][j]);
sr[i][j]+=2;
}
}
if(No()){puts("0");continue;}
s=0,t=1;
printf("%d\n",bsh());
}
return 0;
}
sap
#include<cstdio>
#include<cstring>
const int N=25000;
const int M=100000;
const int INF=0x7fffffff;
int tol,ans,s,t;
int head[N],arc[N],pre[N],dis[N],gap[N];
struct node
{
int y,f,nxt;
}edge[M];
void add(int x,int y,int f)
{
edge[tol].y=y;
edge[tol].f=f;
edge[tol].nxt=head[x];
head[x]=tol++;
edge[tol].y=x;
edge[tol].f=0;
edge[tol].nxt=head[y];
head[y]=tol++;
}
void bfs(int n)
{
int Q[N],front=0,rear=0,i,u,v;
bool vis[N];
memcpy(arc,head,sizeof(head));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(gap,0,sizeof(gap));
for(i=0;i<n;i++)dis[i]=n;
vis[t]=1,dis[t]=0,Q[rear++]=t;
while(front<rear)
{
u=Q[front++];
for(i=head[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].y;
if(!vis[v]&&edge[i-1].f)
{
vis[v]=1;
Q[rear++]=v;
dis[v]=dis[u]+1;
gap[dis[v]]++;
}
}
}
}
void sap(int n)
{
bfs(n);
int arg=INF,u=pre[s]=s;
while(dis[s]<n)
{
L:
for(int& i=arc[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].y;
if(edge[i].f&&dis[u]==dis[v]+1)
{
if(arg>edge[i].f)arg=edge[i].f;
pre[v]=u;u=v;
if(v==t)
{
ans+=arg;
for(u=pre[u];v!=s;v=u,u=pre[u])
{
edge[arc[u]].f-=arg;
edge[arc[u]^1].f+=arg;
}
arg=INF;
}
goto L;
}
}
int min=n;
for(int j=head[u];j!=-1;j=edge[j].nxt)
{
int v=edge[j].y;
if(edge[j].f&&min>dis[v])
{
arc[u]=j;
min=dis[v];
}
}
if(--gap[dis[u]]==0)break;
dis[u]=min+1;
gap[dis[u]]++;
u=pre[u];
}
}
const int X=25;
int H[X],R[X],sr[X][X],sn,m,k,moon;
bool No()
{
int i,j,x;
bool mm[X][X];
memset(mm,0,sizeof(mm));
for(x=1;x<=m;x++){
for(i=1;i<R[x];i++)for(j=0;j<i;j++){
mm[sr[x][i]][sr[x][j]]=1;
mm[sr[x][j]][sr[x][i]]=1;
}
}
int front=0,rear=0,q[X],u;
bool v[X];
memset(v,0,sizeof(v));
q[rear++]=2;v[2]=1;
while(front<rear)
{
u=q[front++];
for(i=1;i<=sn+2;i++)
{
if(mm[u][i]&&!v[i])
{
v[i]=1;
if(i==1)return 0;
q[rear++]=i;
}
}
}
return 1;
}
bool cal(int tmp)
{
int i,j,a,b;
ans=0,tol=0;
memset(head,-1,sizeof(head));
add(s,2,k);
for(i=3;i<=sn+2;i++)for(j=1;j<=tmp;j++)add(i+(j-1)*sn,i+j*sn,INF);
for(i=1;i<=m;i++)for(j=1;j<=tmp;j++)
{
a=sr[i][(j-1)%R[i]];
if(a>2)a+=(j-1)*sn;
b=sr[i][j%R[i]];
if(b>2)b+=j*sn;
add(a,b,H[i]);
}
sap((tmp+1)*sn+3);
return ans==k;
}
int bsh()
{
int l=0,r=1080,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(cal(mid))r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
int i,j,a,b;
while(~scanf("%d%d%d",&sn,&m,&k))
{
for(i=1;i<=m;i++)
{
scanf("%d%d",&H[i],&R[i]);
for(j=0;j<R[i];j++)
{
scanf("%d",&sr[i][j]);
sr[i][j]+=2;
}
}
if(No()){puts("0");continue;}
s=0,t=1;
printf("%d\n",bsh());
}
return 0;
}