P2754 [CTSC1999]家园 无汇源时间分层建图最大流

题目背景

none!

题目描述

由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。

现有 n 个太空站位于地球与月球之间,且有 m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船 i 只可容纳 H[i]个人。每艘太空船将周期性地停靠一系列的太空站,例如:(1,3,4)表示该太空船将周期性地停靠太空站 134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为 1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。

初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。

对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。

输入格式

第 1 行有 3 个正整数 n(太空站个数),m(太空船个数)和 k(需要运送的地球上的人的个数)。其中 n<=13 m<=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

输出 #1复制

5

说明/提示

none!

本蒟蒻调试了半天一直死循环以为是自己的板子有问题 后来发现是T开得太大了QAQ

题解稍后补上

先放代码

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<stack>
#include<stdio.h>
const int maxn = 1e4 + 10;
const int inf = 0x3f3f3f;
int head[maxn];
int dft[maxn];
int cur[maxn];
int tot;
int n, m, S, T, k;
using namespace std;
struct node{
    int to;
    int next;
    int w;
    node() {}
    node(int a, int b, int c) : to(a), next(b), w(c) {}
}edge[maxn * 2];

struct ship{
	int l;
	int sum;
	int d[maxn];
}sp[maxn]; 
void edgeadd(int a, int b, int c){
    edge[tot] = node(b, head[a], c);
    head[a] = tot++;
    edge[tot] = node(a, head[b], 0);
    head[b] = tot++;
}

int bfs(int s, int e){
	queue<int> q;
    memset(dft, 0, sizeof(dft));
    q.push(s);
    dft[s] = 1;
    while(!q.empty()){
        int nw = q.front();
        q.pop();
        for(int i = head[nw]; i != -1; i = edge[i].next){
            int w = edge[i].w;
            int v = edge[i].to;
            if(w <= 0 || dft[v]) continue;
            dft[v] = dft[nw] + 1;
            q.push(v);
        }
    }
    return dft[e]; 
} 
 
int dfs(int s, int e, int f){
    if(s == e || !f) return f;
    int ans = 0;
    for(int i = head[s]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        int w = edge[i].w;
        //cur[s] = i;
        if(dft[v] != dft[s] + 1 || w <= 0)
            continue;
        int we = dfs(v, e, min(w, f - ans));//由于多次增广, 不能为f
        edge[i].w -= we;
        edge[i ^ 1].w += we;
        ans += we;
    }
    if(!ans) dft[s] = -1;
    return ans;
}
void init(){
    memset(head, -1, sizeof(head));
    tot = 0;
}
 
int dinic(int s, int e){
    int cnt = 0;
    while(bfs(s, e)){
        /*for(int i = 0; i <= n; i++){
            cur[i] = head[i];
        } */
        cnt += dfs(s, e, inf);
    }
    return cnt;
}
 
int main(){
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    n += 2;
    S = 0;
    T = 1200;
    init();
    for(int i = 1; i <= m; i++){
		cin >> sp[i].l >> sp[i].sum;
		for(int j = 0; j < sp[i].sum; j++){
			cin >> sp[i].d[j];
			sp[i].d[j] += 2;
		}
    }
    int day = 0;
    int sum = 0;
    while(day <= 500){
    	edgeadd(S, n * day + 2, inf);
    	edgeadd(n * day + 1, T, inf);
    	if(day){
			for(int i = 1; i <= n; i++)
	    		edgeadd( n * (day - 1) + i, n * day + i, inf);
	    	for(int i = 1; i <= m; i++){
	    		int x = sp[i].d[(day - 1) % sp[i].sum];
	    		int y = sp[i].d[day % sp[i].sum];
	    		edgeadd(n * (day - 1) + x, n * day + y, sp[i].l);
			}
	}
		sum += dinic(S, T);
		//cout << sum << endl;
		if(sum >= k){
			cout << day << endl;
			return 0;
		}
		day++;
	}
    cout << "0" <<endl;
    
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值