cogs 736 星际转移
题解:
从小到大枚举答案days,然后网络流验证是否可以全部运走。假设当前验证的答案为days,那么我们就将太空船和太空站都拆成days+1个点,设编号分别为boat[i][1days+1],station[i][1days+1]。
- 如果说boat[i]在第j天在地球,那么此时boat[i][j]可以接受流量上限为H[i]的人上船,因此从S向boat[i][j]连边,容量H[i]。
- 如果boat[i]第j天在月球,此时boat[i][j]可以释放上限为H[i]的流量,因此boat[i][j]到T连边,容量H[i]。
- boat[i]第j天在太空站station[k],那么双方可以进行交换,boat[i][j]与station[k][j]互相连边,容量均为H[i]。
- 注意到boat[i]在第j天的流量是可以下传到第j+1天的,所以boat[i][j]向boat[i][j+1]连边容量为H[i]。
- 注意到太空站也是可以下传的,station[i][j]向station[i][j+1]连容量为INF的边。
然后跑一下最大流,判断是否最大流小于人数,如果小于,则days再加一,在上一次的图上再加入一层点接着跑,否则结束输出days即可。
至于判断无解,我是判断如果days=1000都没结束就输出无解。
code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define fcl fclose(stdin); fclose(stdout); return 0
int n,m,K,days,S,T,res=0,cnt;
int H[30],r[30],t[30][20];
const int INF=0x7f7f7f7f;
struct EDGE{
int to,next,flow;
}edge[1000010];
int head[100010],tot=1;
inline void AddEdge(int a,int b,int c){
edge[++tot].to=b;
edge[tot].flow=c;
edge[tot].next=head[a];
head[a]=tot;
}
inline void Add(int a,int b,int c){
AddEdge(a,b,c); AddEdge(b,a,0);
}
int cur[100010],dis[100010],Q[100010];
#define ty (edge[x].to)
bool Bfs(){
memset(dis,0x7f,(cnt+1)<<2); dis[S]=0;
int s=1,t=1,u; Q[1]=S;
while(s<=t){
u=Q[s++];
for(int x=head[u];x;x=edge[x].next)
if(edge[x].flow&&dis[ty]==INF)
dis[ty]=dis[u]+1,Q[++t]=ty;
}
return dis[T]!=INF;
}
int Dfs(int u,int a){
if(u==T||a==0) return a;
int f2=0,f;
for(int& x=cur[u];x;x=edge[x].next){
if(edge[x].flow&&dis[ty]==dis[u]+1){
f=Dfs(ty,min(a,edge[x].flow));
edge[x].flow-=f; edge[x^1].flow+=f;
f2+=f; a-=f;
if(a==0) break;
}
}
return f2;
}
bool Judge(){
for(int i=1;i<=m;++i){
int x=days%r[i];
if(t[i][x]==0) Add(S,cnt+i,H[i]);
else if(t[i][x]==-1) Add(cnt+i,T,H[i]);
else AddEdge(cnt+i,cnt+m+t[i][x],INF),Add(cnt+m+t[i][x],cnt+i,INF);
Add(cnt+i,cnt+i+n+m,H[i]);
}
for(int i=1;i<=n;++i) Add(cnt+m+i,cnt+n+m+m+i,INF);
cnt+=(n+m);
while(Bfs()){
memcpy(cur,head,(cnt+1)<<2);
res+=Dfs(S,INF);
}
if(res<K) return true;
return false;
}
int main(){
freopen("home.in","r",stdin);
freopen("home.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
S=1,T=2,cnt=2;
for(int i=1;i<=m;++i){
scanf("%d%d",&H[i],&r[i]);
for(int j=0;j<r[i];++j) scanf("%d",&t[i][j]);
}
if(K==0){puts("0");fcl;}
for(;days<1000&&Judge();++days);
if(days==1000) days=0;
printf("%d
",days);
fcl;
}