zoukankan      html  css  js  c++  java
  • 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;
    } 
  • 相关阅读:
    【转载】如果你看完这篇文章还不懂计算机时间,那就掐死我吧
    记录 C#中 LINQ 和 SQL 语句 的一些操作数据集合
    记录mysql 存储过程中循环临时表
    记录一个有趣的dotnet开源库。
    将Quartz.Net用于ASP.NET Core 3.0应用程序中的,并实现通过依赖注入获取其他服务
    web api中接收 复杂类型数组参数(对象数组参数)
    网页支付宝支付,通过form表单提交,在苹果手机上无法跳转
    阿里云服务器上搭建FTP服务器,连接时出现:读取目录列表失败的解决办法
    css选择器及float(浮动)
    盒子四大元素
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13324814.html
Copyright © 2011-2022 走看看