[网络流24题]星际转移问题

Description

由于人类对自然资源的消耗,人们意识到大约在$2300$年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,$2177$年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。现有$n$个太空站位于地球与月球之间,且有$m$艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船$i$只可容纳$H_i$个人。每艘太空船将周期性地停靠一系列的太空站,
例如:$(1,3,4)$表示该太空船将周期性地停靠太空站$134134134...$。每一艘太空船从一个太空站驶往任一太空站耗时均为$1$。人们只能在太空船停靠太空站(或月球、地球)时上、下船。

初始时所有人全在地球上,太空船全在初始站。求让所有人全部转移到月球上所需最短用时。

Input

第$1$行有$3$个正整数$n$(太空站个数),$m$(太空船个数)和$k$(需要运送的地球上的人的个数)。

接下来的$m$行给出太空船的信息。第$i+1$行说明太空船$p_i$。第$1$个数表示$p_i$可容纳的人数$H_i$;第$2$个数表示$p_i$一个周期停靠的太空站个数$r_i$;随后$r_i$个数是停靠的太空站的编号:$S_{i,1},S_{i,2},...,S_{i,r}$,地球用$0$表示,月球用$-1$表示。时刻$0$时,所有太空船都在初始站,然后开始运行。在时刻$1,2,3...$等正点时刻各艘太空船停靠相应的太空站。人只有在$0,1,2...$等正点时刻才能上下太空船。

Output

一行一个整数,表示将全部人员安全转移所需最短用时。如果问题无解,则输出$0$。

Sample Input

2 2 1
1 3 0 1 2
1 3 1 2 –1

Sample Output

5

HINT

$1\;\leq\;m\;\leq\;13,1\;\leq\;n\;\leq\;20,1\;\leq\;k\;\leq\;50,1\;\leq\;r\;\leq\;n+2$.

Solution

遍历判断从地球到月球是否存在一条路径,若不存在,则无解.

将每个点按时间拆成$d$个点,$x_{i,d}$表示第$i$个太空站第$d$天的情况.

顺序枚举答案$d$.

从$s$到$x_{0,d}$连一条容量为$+\infty$的有向边,

从$x_{-1,d}$到$t$连一条容量为$+\infty$的有向边,

从$x_{i,d-1}$到$x_{i,d}$连一条容量为$+\infty$的有向边,

若存在某艘太空船$k$,第$d-1$天在$i$,第$d$天在$j$,从$x_{i,d-1}$到$x_{j,d}$连一条容量为$H_k$的有向边.

求最大流,若流量$\;\leq\;k$,则$d$为答案.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 25
#define K 1105
#define M 77005
using namespace std;
struct graph{
    int nxt,to,f;
}e[M],e1[K];
int a[N][N],h[N],r[N],g[K],g1[N],dep[K],n,m,k,s,t,fl,tot,cnt;
bool v[N];
queue<int> q;
inline void added(int x,int y){
    e1[++cnt].nxt=g1[x];g1[x]=cnt;e1[cnt].to=y;
}
inline void addedge(int x,int y,int f){
    e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
}
inline void adde(int x,int y,int f){
    addedge(x,y,f);addedge(y,x,0); 
} 
inline int f(int d){
    return tot*d;
}
inline bool bfs(int u){
    memset(dep,0,sizeof(dep));
    q.push(u);dep[u]=1;
    while(!q.empty()){
        u=q.front();q.pop();
        for(int i=g[u];i;i=e[i].nxt)
            if(e[i].f>0&&!dep[e[i].to]){
                q.push(e[i].to);
                dep[e[i].to]=dep[u]+1;
            }
    }
    return dep[t];
}
inline int dfs(int u,int f){
    int ret=0;
    if(u==t) return f;
    for(int i=g[u],d;i&&f;i=e[i].nxt)
        if(e[i].f>0&&dep[e[i].to]>dep[u]){
            d=dfs(e[i].to,min(f,e[i].f));
            ret+=d;f-=d;e[i].f-=d;e[i^1].f+=d;
        }
    return ret;
}
inline int dinic(){
    int ret=0;
    while(true){
        if(!bfs(s)) return ret;
        ret+=dfs(s,M);
    }
}
inline bool chk(int u){
    v[u]=true;q.push(u);
    while(!q.empty()){
        u=q.front();q.pop();
        for(int i=g1[u];i;i=e1[i].nxt)
            if(!v[e1[i].to]){
                if(e1[i].to==n+2) return true; 
                q.push(e1[i].to);v[e1[i].to]=true;
            }
    }
    return false;
}
inline void Aireen(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;++i){
        scanf("%d%d",&h[i],&r[i]);
        for(int j=0;j<r[i];++j){
            scanf("%d",&a[i][j]);
            if(!a[i][j]) a[i][j]=n+1;
            else if(a[i][j]<0) a[i][j]=n+2;
        }
        for(int j=1;j<r[i];++j)
            added(a[i][j-1],a[i][j]);
        if(r[i]>1) added(a[i][r[i]-1],a[i][0]);
    }
    if(!chk(n+1)){
        puts("0");return;
    }
    s=0;t=K-1;tot=n+2;cnt=1; 
    adde(0,n+1,M);adde(n+2,t,M);
    for(int d=1;;++d){
        adde(s,n+1+f(d),M);adde(n+2+f(d),t,M);
        for(int i=1;i<=n;++i)
            adde(i+f(d-1),i+f(d),M);
        for(int i=1;i<=m;++i)
            adde(a[i][(d-1)%r[i]]+f(d-1),a[i][d%r[i]]+f(d),h[i]);
        fl+=dinic();
        if(fl>=k){
            printf("%d\n",d);return;
        }
    }    
}
int main(){
    freopen("home.in","r",stdin);
    freopen("home.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
posted @ 2017-01-02 22:19  Aireen_Ye  阅读(208)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.