网络流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\)因素就是时间。于是考虑从时间分层。
建图与实现
把天数当作层数,从第一天开始不断递增,也就是在对每一层跑一边网络流,每一层被上一层决定。
层与层有若干边,这种边分为两种:
- 太空船会随着时间移动,前一天到后一天连接边,容量为飞船上限。
- 太空站可以留人,也就是说,前一天会与后一天分层,容量为无穷。
现在边分层边跑最大流,知道最大流超过人数上限\(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;
}