nbu 2431 星际转移

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值