网络流24题(十三)

网络流24题(十三)

十三、星际转移问题

题目描述

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

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

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

输入格式

输入的第一行是三个用空格隔开的整数,分别代表太空站个数 \(n\),太空船个数 \(m\) 和地球上的人数 \(k\)

第 2 到第 \((m + 1)\) 行,每行给出一艘太空船的信息,第 \((i + 1)\) 行的第一个整数 \(h_i\)​ 代表第 \(i\) 艘太空船可容纳的人数。随后有一个整数 \(r_i\)​,代表第 \(i\) 艘太空船停靠的站点数。之后有 \(r_i\)​ 个整数,依次代表该太空船停靠站点的编号 \(S_{i, j}\)​,其中太空站自 1 至 \(n\) 编号,地球编号为 0,月球编号为 −1。

输出格式

输出一行一个整数,代表将所有人转移到月球上的最短用时。若无解则输出 0。

题解

模型

分层图网络流
讲一下分层图:
一个点会随着另外一个因素\(X\)的变化而变化,我们可以把\(X\)的变化看作不同的层\(j\)。这样本来每一个点\(i\),随着\(X\)就会生成\([j,i]\)这样不同的状态,我们可以把这些状态看作新的点,并建立一张新图,这样的图就是分层图。
而本题\(X\)因素就是时间。于是考虑从时间分层。

建图与实现

把天数当作层数,从第一天开始不断递增,也就是在对每一层跑一边网络流,每一层被上一层决定。
层与层有若干边,这种边分为两种:

  1. 太空船会随着时间移动,前一天到后一天连接边,容量为飞船上限。
  2. 太空站可以留人,也就是说,前一天会与后一天分层,容量为无穷。

现在边分层边跑最大流,知道最大流超过人数上限\(k\),那么有解,解为天数。

const ll inf = 1e9+50;
const ll N = 1e4+50,M = 5e4+50;
struct Edge{
    ll to,w,nxt;
}edge[M*2];
ll head[N],cnt = 1;
void add(ll u,ll v,ll w){
    edge[++cnt] = {v,w,head[u]};
    head[u] = cnt;
}
void add2(ll u,ll v,ll w){
    add(u,v,w);
    add(v,u,0);
}
ll s,t,lv[N],cur[N];
bool bfs(){
    memset(lv,-1,sizeof lv);
    lv[s] = 0;
    memcpy(cur,head,sizeof head);
    queue<ll>q;q.push(s);
    while(!q.empty()){
        ll p = q.front();q.pop();
        for(ll eg = head[p];eg;eg = edge[eg].nxt){
            ll to = edge[eg].to,vol = edge[eg].w;
            if(vol > 0 && lv[to] == -1) lv[to] = lv[p]+1,q.push(to);
        }
    }
    return lv[t] != -1;
}
ll dfs(ll p = s,ll flow = inf){
    if(p == t)return flow;
    ll rmn = flow;
    for(ll &eg = cur[p];eg;eg = edge[eg].nxt){
        if(!rmn)break;
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol > 0 && lv[to] == lv[p]+1){
            ll c = dfs(to,min(vol,rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg^1].w += c;
        }
    }
    return flow-rmn;
}
ll dinic(){
    ll ans = 0;
    while(bfs())ans+=dfs();
    return  ans;
}
ll h[N],r[N],pos[N] = {0},p[N][50];
int main(){
    ios::sync_with_stdio(false);
    ll n,m,k;cin>>n>>m>>k;
    n = n+2;
    for(ll i = 1;i <= m;i++){
        cin>>h[i]>>r[i];
        for(ll j = 0;j < r[i];j++){
            ll x;cin>>x;
            x++;
            if(x == 0) x = n;
            p[i][j] = x;
        }
    }
    s = 0,t = 100*n;
    add2(s,1,inf);add2(n,t,inf);
    ll flow = 0;
    for(ll d = 1;d <= 100;d++){
        add2(s,d*n+1,inf);add2(d*n+n,t,inf);
        for(ll i = 1;i <= m;i++){
            ll u = p[i][pos[i]];
            pos[i] = (pos[i]+1)%r[i];
            ll v = p[i][pos[i]];
            add2((d-1)*n+u,d*n+v,h[i]);
        }
        for(ll i = 2;i < n;i++)add2((d-1)*n+i,d*n+i,inf);
        //cout<<flow<<endl;
        flow+=dinic();
        if(flow >= k){
            cout<<d<<endl;
            return 0;
        }
    }
    cout<<0<<endl;
    return 0;
}
posted @ 2021-10-09 18:17  Paranoid5  阅读(34)  评论(0编辑  收藏  举报