zoukankan      html  css  js  c++  java
  • 洛谷 P2762 太空飞行计划问题

    题目背景

    题目描述

    W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。

    对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

    输入输出格式

    输入格式:

    第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。

    输出格式:

    第1 行是实验编号;第2行是仪器编号;最后一行是净收益。

    输入输出样例

    输入样例#1:
    2 3
    10 1 2
    25 2 3
    5 6 7
    输出样例#1:
    1 2
    1 2 3
    17

    说明

    感谢@zhouyonglong 提供spj//spj好评

    解题思路

      最大权闭合子图的入门题,这个模型我是看这篇博文看懂的。图要这样建——

      从S向所有实验连边,边容量为该实验收入,从每个实验向每个需要的设备连边,边权为inf,从每个设备向T连边,边权为该设备费用。

      答案为所有实验的总收入(不用减去成本)的总和减去上图从S到T的最大流。

    源代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    int n,m;
    int s,t;
    struct Edge{
        int next,to,f;
    }e[100010]={0};
    int cnt=2,head[100010]={0};
    void add(int u,int v,int f)
    {
        e[cnt]={head[u],v,f};
        head[u]=cnt++;
        e[cnt]={head[v],u,0};
        head[v]=cnt++;
    }
    
    int dis[100010]={0};
    bool vis[100010]={0};
    bool bfs()
    {
        memset(dis,0,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[s]=1;
        std::queue<int> q;
        q.push(s);
        vis[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].to;
                if(!dis[v]&&e[i].f>0)
                {
                    dis[v]=dis[u]+1;
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
        return dis[t]!=0;
    }
    
    int dfs(int u,int flow)
    {
        if(u==t||flow==0) return flow;
        int flow_sum=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to,f=e[i].f;
            if(dis[v]!=dis[u]+1||f==0) continue;
            int temp=dfs(v,std::min(flow-flow_sum,f));
            e[i].f-=temp;
            e[i^1].f+=temp;
            flow_sum+=temp;
            if(flow_sum>=flow) break;
        }
        if(!flow_sum) dis[u]=-1;
        return flow_sum;
    }
    
    int dinic()
    {
        int ans=0;
        while(bfs())
        {
            while(int temp=dfs(s,0x7fffffff))
                ans+=temp;
        }
        return ans;
    }
    
    int main()
    {
        //freopen("shuttle.in","r",stdin);
        //freopen("shuttle.out","w",stdout);
        scanf("%d%d",&m,&n);
        s=n+m+1,t=s+1;
        int ans=0;
        for(int i=1,w;i<=m;i++)
        {
            scanf("%d",&w);
            ans+=w;
            add(s,i,w);
            char ch=getchar();
            while(ch==' ')
            {
                scanf("%d%c",&w,&ch);
                add(i,w+m,0x7fffffff);
            }
        }
        for(int i=1,w;i<=n;i++)
        {
            scanf("%d",&w);
            add(m+i,t,w);
        }
        int temp=ans-dinic();
    
        for(int i=1;i<=m;i++)
            if(vis[i]) printf("%d ",i);
        printf("
    ");
        for(int i=1;i<=n;i++)
            if(vis[i+m]) printf("%d ",i);
        /*for(int i=head[s];i;i=e[i].next)
            if(e[i^1].f>0) printf("%d ",e[i].to);
        printf("
    ");
        for(int i=head[t];i;i=e[i].next)
            if(e[i].f>0) printf("%d ",e[i].to-m);
        */
        putchar('
    ');
        printf("%d
    ",temp);
        return 0;
    }
  • 相关阅读:
    选择结构
    算法和流程图
    存储信息和信息运算
    计算机组成原理
    计算机硬件组装
    认识计算机硬件
    认识操作系统
    DOS简介
    计算机软件知识
    易企cms截取字段方法
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/7100586.html
Copyright © 2011-2022 走看看