[网络流24题] 13. 星际转移问题 解题报告
Posted brucew-07
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[网络流24题] 13. 星际转移问题 解题报告相关的知识,希望对你有一定的参考价值。
题意
有 (n) 个太空站, (m) 艘太空船,
太空船 (i) 一次能容下 (h_i) 个人,
每艘太空船会按照自己的航线循环行驶, 每行驶一个站点需要一个单位时间,
求从节点 (0) 到节点 (n+1) 所需的最小时间.
思路
一道一开始完全没有思路的题, 后来发现姆爷又发了新专, 果断地剁手后听了一会, 这道题就想出来了......
总思路是把每个太空站都按时间分为若干个节点,
也就是说, 每加一个单位时间, 我们就把这总共 (n+2) 个点全部建一遍 (包括 (0) 节点和 (n+1) 节点).
对于每艘太空船, 我们都按照它的航线向右建边, 也就是向它下一个单位时刻会到达的节点连边,
除此之外, 每个时刻的每个太空站还要向下一时刻的自己连边, 容量为 (inf), 表示在等太空船.
题解的做法是先用并查集判断是否能到达终点, 然后按时间依次加点加边, 在残量网络上跑最大流就行了.
我比较蠢.....先随便选了一个很大的数作为总时间, 然后直接把整张图建出来跑了一个最小费用最大流...
代码
#include<bits/stdc++.h>
using namespace std;
const int _=20+7;
const int __=700+7;
const int ___=3e3+7;
const int inf=0x3f3f3f3f;
int n,m,num,S,T,des,st[_],dis[__],max_flow,ans,limit=30;
int lst[__],nxt[___],to[___],c[___],w[___],tot=1;
bool vis[__];
queue<int> q;
void add(int x,int y,int cap,int wgt){
//printf("(%d,%d,%d,%d)
",x,y,cap,wgt);
nxt[++tot]=lst[x]; to[tot]=y; c[tot]=cap; w[tot]=wgt; lst[x]=tot;
nxt[++tot]=lst[y]; to[tot]=x; c[tot]=0; w[tot]=-wgt; lst[y]=tot;
}
void init(){
cin>>n>>m>>num;
S=(n+2)*(limit+1); T=S+1; des=T+1;
int h,cy;
for(int i=1;i<=m;i++){
scanf("%d%d",&h,&cy);
for(int j=1;j<=cy;j++){
scanf("%d",&st[j]);
if(st[j]==-1) st[j]=n+1;
}
int time=0,j=1,t=0;
while(time<limit){
int x=st[j],y=st[j==cy ?1 :j+1];
add(x+t,y+t+n+2,h,1);
t+=n+2; time++;
j= j==cy ?1 :j+1;
}
}
for(int t=0;t<limit;t++){
int tt=t*(n+2);
for(int i=0;i<=n+1;i++)
add(i+tt,i+tt+n+2,inf,1);
}
add(S,0,num,0);
add(des,T,num,0);
for(int i=0;i<=limit;i++)
add(n+1+i*(n+2),des,inf,0);
}
bool SPFA(){
for(int i=0;i<=des;i++){ dis[i]=inf; vis[i]=0; }
while(!q.empty()) q.pop();
dis[S]=0; q.push(S);
while(!q.empty()){
int u=q.front(); q.pop();
vis[u]=0;
for(int i=lst[u];i;i=nxt[i]){
int v=to[i];
if(!c[i]||dis[v]<=dis[u]+w[i]) continue;
dis[v]=dis[u]+w[i];
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
memset(vis,0,sizeof(vis));
return dis[T]!=inf;
}
int dfs(int u,int flow){
if(u==T) return flow;
int rest=flow; vis[u]=1;
for(int i=lst[u];i;i=nxt[i]){
int v=to[i];
if(vis[v]||dis[v]!=dis[u]+w[i]||!c[i]) continue;
int cst=dfs(v,min(rest,c[i]));
if(cst==0) dis[v]=inf;
else{
c[i]-=cst; c[i^1]+=cst;
rest-=cst;
}
}
vis[u]=0;
return flow-rest;
}
void Dinic(){
int flow;
while(SPFA())
do{
flow=dfs(S,inf);
max_flow+=flow;
}while(flow);
//printf("max_flow: %d
",max_flow);
}
void print(){
for(int i=lst[des];i;i=nxt[i])
if(to[i]!=T&&c[i]&&to[i]>ans) ans=to[i];
ans=(ans-(n+1))/(n+2);
printf("%d
",ans);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("x.in","r",stdin);
#endif
init();
Dinic();
if(max_flow<num) puts("0");
else print();
return 0;
}
以上是关于[网络流24题] 13. 星际转移问题 解题报告的主要内容,如果未能解决你的问题,请参考以下文章