網路流24題(十三)
網路流24題(十三)
十三、星際轉移問題
題目描述
由於人類對自然資源的消耗,人們意識到大約在 2300 年之後,地球就不能再居住了。於是在月球上建立了新的綠地,以便在需要時移民。令人意想不到的是,2177 年冬由於未知的原因,地球環境發生了連鎖崩潰,人類必須在最短的時間內遷往月球。
現有 \(n\) 個太空站位於地球與月球之間,且有 \(m\) 艘公共交通太空船在其間來回穿梭。每個太空站可容納無限多的人,而太空船的容量是有限的,第 \(i\) 艘太空船隻可容納 \(h_i\) 個人。每艘太空船將週期性地停靠一系列的太空站,例如 \((1,3,4)\) 表示該太空船將週期性地停靠太空站 134134134\(\dots\)
初始時所有人全在地球上,太空船全在初始站。試設計一個演算法,找出讓所有人儘快地全部轉移到月球上的運輸方案。
輸入格式
輸入的第一行是三個用空格隔開的整數,分別代表太空站個數 \(n\),太空船個數 \(m\) 和地球上的人數 \(k\)。
第 2 到第 \((m + 1)\) 行,每行給出一艘太空船的資訊,第 \((i + 1)\) 行的第一個整數 \(h_i\) 代表第 \(i\) 艘太空船可容納的人數。隨後有一個整數 \(r_i\),代表第 \(i\)
輸出格式
輸出一行一個整數,代表將所有人轉移到月球上的最短用時。若無解則輸出 0。
題解
模型
分層圖網路流
講一下分層圖:
一個點會隨著另外一個因素\(X\)的變化而變化,我們可以把\(X\)的變化看作不同的層\(j\)。這樣本來每一個點\(i\),隨著\(X\)就會生成\([j,i]\)這樣不同的狀態,我們可以把這些狀態看作新的點,並建立一張新圖,這樣的圖就是分層圖。
而本題\(X\)
建圖與實現
把天數當作層數,從第一天開始不斷遞增,也就是在對每一層跑一邊網路流,每一層被上一層決定。
層與層有若干邊,這種邊分為兩種:
- 太空船會隨著時間移動,前一天到後一天連線邊,容量為飛船上限。
- 太空站可以留人,也就是說,前一天會與後一天分層,容量為無窮。
現在邊分層邊跑最大流,知道最大流超過人數上限\(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;
}