P2754 星际转移问题(最大流)

题目描述

由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。

现有 nn 个太空站位于地球与月球之间,且有 mm 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而太空船的容量是有限的,第 ii 艘太空船只可容纳 h_ihi 个人。每艘太空船将周期性地停靠一系列的太空站,例如 (1,3,4)(1,3,4) 表示该太空船将周期性地停靠太空站 134134134dots134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为 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
");
    else
        printf("%d
",ans);
    return 0;
} 
原文地址:https://www.cnblogs.com/zhanglichen/p/13324814.html