1. 程式人生 > 實用技巧 >P2754 星際轉移問題(最大流)

P2754 星際轉移問題(最大流)

題目描述

由於人類對自然資源的消耗,人們意識到大約在 2300 年之後,地球就不能再居住了。於是在月球上建立了新的綠地,以便在需要時移民。令人意想不到的是,2177 年冬由於未知的原因,地球環境發生了連鎖崩潰,人類必須在最短的時間內遷往月球。

現有nn個太空站位於地球與月球之間,且有mm艘公共交通太空船在其間來回穿梭。每個太空站可容納無限多的人,而太空船的容量是有限的,第ii艘太空船隻可容納h_ihi個人。每艘太空船將週期性地停靠一系列的太空站,例如(1,3,4)(1,3,4)表示該太空船將週期性地停靠太空站134134134\dots134134134…。每一艘太空船從一個太空站駛往任一太空站耗時均為11。人們只能在太空船停靠太空站(或月球、地球)時上、下船。

初始時所有人全在地球上,太空船全在初始站。試設計一個演算法,找出讓所有人儘快地全部轉移到月球上的運輸方案。

輸入格式

輸入的第一行是三個用空格隔開的整數,分別代表太空站個數nn,太空船個數mm和地球上的人數kk。

22到第(m + 1)(m+1)行,每行給出一艘太空船的資訊,第(i + 1)(i+1)行的第一個整數h_ihi代表第ii艘太空船可容納的人數。隨後有一個整數r_iri,代表第ii艘太空船停靠的站點數。之後有r_iri個整數,依次代表該太空船停靠站點的編號S_{i, j}Si,j,其中太空站自11至nn編號,地球編號為00,月球編號為-11。

輸出格式

輸出一行一個整數,代表將所有人轉移到月球上的最短用時。若無解則輸出00。

/*
 *從源點向每一天的地球連一條inf
 *從每一天的地球向匯點連一條inf
 *從上一天的每個節點向當天的對應節點連一條inf
 *針對每一艘飛船,上一天的位置和這一天的位置連一天邊,容量為飛船的人數
 *每次新加一天跑一遍Dinic,直到答案超過目標人數 
 */
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const int inf=1e9;
int head[maxn];
struct node {
    int u,v,w,nxt;
}edge[maxn];
int tot=0;
void addedge (int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].u=v; edge[tot].v=u; edge[tot].w=0; edge[tot].nxt=head[v]; head[v]=tot++; } int dep[maxn]; int inq[maxn]; int cur[maxn]; int wjm; int maxflow=0; int s,t; bool bfs () { for (int i=0;i<maxn;i++) { cur[i]=head[i]; dep[i]=inf; inq[i]=0; } dep[s]=0; queue<int> q; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for (int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (dep[v]>dep[u]+1&&edge[i].w) { dep[v]=dep[u]+1; if (inq[v]==0) { q.push(v); inq[v]=1; } } } } if (dep[t]!=inf) return 1; return 0; } int dfs (int u,int flow) { int increase=0; if (u==t) { wjm=1; maxflow+=flow; return flow; } int used=0; for (int i=cur[u];i!=-1;i=edge[i].nxt) { cur[u]=i; int v=edge[i].v; if (edge[i].w&&dep[v]==dep[u]+1) { if (increase=dfs(v,min(flow-used,edge[i].w))) { used+=increase; edge[i].w-=increase; edge[i^1].w+=increase; if (used==flow) break; } } } return used; } int Dinic () { maxflow=0; while (bfs()) { wjm=1; while (wjm==1) { wjm=0; dfs(s,inf); } } return maxflow; } struct position { int h; int nxt[205]; int zq; }p[maxn]; int main () { for (int i=0;i<maxn;i++) head[i]=-1; int n,m,k; scanf("%d%d%d",&n,&m,&k); n+=2; for (int i=1;i<=m;i++) { scanf("%d%d",&p[i].h,&p[i].zq); for (int j=0;j<p[i].zq;j++) { scanf("%d",&p[i].nxt[j]); p[i].nxt[j]+=2; } } //0為源點,(ans-1)*(2+m)為地球, (ans-1)*(2+m)+i表示第ans天的第i個站,(ans)*(2+m)-1表示第i天的月球 s=0,t=1e5; int ans; int sum=0; while (ans<500) { addedge(ans*n+1,t,inf); addedge(s,ans*n+2,inf); if (ans) { for (int i=1;i<=n;i++) addedge((ans-1)*n+i,ans*n+i,inf); for (int i=1;i<=m;i++) { int x=p[i].nxt[(ans-1)%p[i].zq]; int y=p[i].nxt[(ans)%p[i].zq]; addedge((ans-1)*n+x,ans*n+y,p[i].h); } } sum+=Dinic(); if (sum>=k) break; ans++; } if (ans==500) printf("0\n"); else printf("%d\n",ans); return 0; }