列表

详情


NC213825. [网络流24题]星际转移问题

描述

由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。现有n个太空站位于地球与月球之间,且有m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船i 只可容纳H[i]个人。每艘太空船将周期性地停靠一系列的太空站,例如:(1,3,4)表示该太空船将周期性地停靠太空站134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。
编程任务:对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。

输入描述

第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…等正点时刻才能上下太空船。

输出描述

程序运行结束时,将全部人员安全转移所需的时间输出。如果问题无解,则输出0。

示例1

输入:

2 2 1
1 3 0 1 2
1 3 1 2 -1

输出:

5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 6ms, 内存消耗: 3624K, 提交时间: 2022-12-28 13:21:19

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 500010, INF = 0x3f3f3f3f;
int h[N], e[M], ne[M], f[M], idx, d[N], n, m, k, S, T, cur[M], H[N], p[N];
vector<int>num[N];
void add(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx ++;
    e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx ++; 
}

int find(int x)
{
	if(p[x] != x) return p[x] = find(p[x]);
	return p[x];
}
bool bfs()
{
    queue<int>q;
    memset(d, -1, sizeof d);
    q.push(S);
    d[S] = 0;
    cur[S] = h[S];
    while(!q.empty())
    {
        auto t = q.front();
        q.pop();
        
        for(int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if((d[j] == -1) && f[i])
            {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if(j == T) return true;
                q.push(j);
            }
        }
    }
    return false;
}

int find(int u, int limit)
{
    if(u == T) return limit;
    int flow = 0;
    for(int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        int j = e[i];
        cur[u] = i;
        if((d[j] == d[u] + 1) && f[i])
        {
            int t = find(j, min(f[i], limit - flow));
            if(!t) d[j] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic()
{
    int r = 0, flow;
    while(bfs()) while(flow = find(S, 0x3f3f3f3f)) r += flow;
    	
    return r;
}
int get(int day, int id)
{
	return day * (n + 2) + id;
}
int main()
{
	cin >> n >> m >> k;
	memset(h, -1, sizeof h);

	for(int i = 0; i <= n + 1; i ++ ) p[i] = i;
	for(int i = 1; i <= m; i ++ )
	{
		cin >> H[i];
		int x;
		cin >> x;
		int id;
		while(x -- ) 	
		{
			cin >> id;
			if(id == -1) id = n + 1;
			num[i].push_back(id);
		}

		for(int j = 1; j < num[i].size(); j ++ )
		{
			int a = num[i][j - 1], b = num[i][j];
			a = find(a), b = find(b);
			p[a] = b;
		}
	}

	if(find(0) != find(n + 1)) 
	{
		cout << 0 << '\n';
		return 0;
	}

	S = N - 2, T = N - 1;

	add(S, get(0, 0), k);
	add(get(0, n + 1), T, INF);
	int sum = 0;


	for(int i = 1; ; i ++ )
	{
	    add(get(i, n + 1), T, INF);
		for(int j = 0; j <= n; j ++ ) add(get(i - 1, j), get(i, j), INF);

		for(int j = 1; j <= m; j ++ )
		{
		    int a = num[j][(i - 1) % (int)num[j].size()], b = num[j][i % (int)num[j].size()];
		    add(get(i - 1, a), get(i, b), H[j]);
		}
		sum += dinic();
		if(sum >= k) 
		{
			cout << i << '\n';
			return 0;
		}
	}
}

C++(clang++ 11.0.1) 解法, 执行用时: 64ms, 内存消耗: 728K, 提交时间: 2022-10-04 22:05:18

#include <bits/stdc++.h>
#define inf 100
#define N 10010
using namespace std;
int n,m,k,P[21],s=1,t=0;
vector<int> e[21];
int l,r,mid;
struct edg{
	int t,next,w;
}edge[10*N];
int d[N],q[N]; // d[i]是层数,q是手工栈 
int head[N],hcnt=-1;
int ans;
void addedge(int x,int y,int w){
	edge[++hcnt].t=y;
	edge[hcnt].w=w;
	edge[hcnt].next=head[x];
	head[x]=hcnt;
}
bool makelevel(int s,int t){
	memset(d,0,sizeof(d));
	memset(q,0,sizeof(q));
	d[s]=1;
	int tl=0,tr=0;
	q[tr++]=s;
	while(tl<tr){
		int x=q[tl++];
		if(x==t) return true;
		for(int i=head[x];i!=-1;i=edge[i].next){
			if(d[edge[i].t]==0 && edge[i].w!=0){
				q[tr++]=edge[i].t;
				d[edge[i].t]=d[x]+1;
			}
		}
	} 
	return false;
}
int dfs(int x,int flow,int t){
	if(x==t) return flow;
	int sum=0;
	for(int i=head[x];i!=-1;i=edge[i].next){
		if(edge[i].w!=0 && d[edge[i].t]==d[x]+1){
			int tmp=dfs(edge[i].t,min(edge[i].w,flow-sum),t);
			edge[i].w-=tmp;
			edge[i^1].w+=tmp;
			sum+=tmp;
			if(sum==flow) return sum;
		}
	}
	return sum;
}
signed main(){
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++){
		scanf("%d",&P[i]);
		scanf("%d",&r);
		for(int j=1;j<=r;j++){
			scanf("%d",&l);
			e[i].push_back(l+1);
		}
	}
	int day=0;
    while(day<500){
        for(int i=1;i<=(n+1);i++){
            addedge(day*(n+1)+i,(day+1)*(n+1)+i,inf);
			addedge((day+1)*(n+1)+i,day*(n+1)+i,0);
        }
        for(int i=1;i<=m;i++){
            int siz=e[i].size();
			int from=day*(n+1)+e[i][day%siz];
			int to=(day+1)*(n+1)+e[i][(day+1)%siz];
			if(e[i][day%siz]==t ) from=t;
			if(e[i][(day+1)%siz]==t ) to=t;
			addedge(from,to,P[i]);
			addedge(to,from,0);
        }
        while(makelevel(s,t)){
            ans+=dfs(s,inf,t);
        }
        day++;
        if(ans>=k) break;
        
    }
	if(day==500)printf("0");
    else printf("%d\n",day);
	return 0;
} 

上一题