1. 程式人生 > 其它 >網路流24題(十三)

網路流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;
}