洛谷 P2762 太空飞行计划问题

简介: 题目背景 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。

题目背景

题目描述

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("\n");
    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("\n");
    for(int i=head[t];i;i=e[i].next)
        if(e[i].f>0) printf("%d ",e[i].to-m);
    */
    putchar('\n');
    printf("%d\n",temp);
    return 0;
}

 

目录
相关文章
AcWing 2060. 奶牛选美(每日一题)
AcWing 2060. 奶牛选美(每日一题)
|
4月前
【洛谷】P2004 领地选择
洛谷 P2004 领地选择
43 2
【洛谷】P2004 领地选择
|
4月前
【洛谷】P1163 银行贷款
洛谷P1163 银行贷款
43 0
【洛谷】P1163 银行贷款
|
机器学习/深度学习
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
71 0
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
79 0
洛谷1102 A-B 暴力法
判断第 i 个数和 i 之后的每一个数的绝对值是否等于目标结果
|
存储
AcWing第98和99周赛
AcWing第98和99周赛
100 0
|
机器学习/深度学习 人工智能 安全
【AcWing周赛】AcWing第86场周赛
目录 <一>AcWing 4794. 健身 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <二>AcWing 4795. 安全区域 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <三>AcWing 4796. 删除序列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
80 0
|
机器学习/深度学习 编译器
【AcWing周赛】AcWing第85场周赛
目录 &lt;一&gt;Acwing 4791. 死或生 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;二&gt;Acwing 4792. 最大价值 一、题目 1、原题链接 2、题目描述 二、解题报告: 1、思路分析 2、时间复杂度 3、代码详解 &lt;三&gt;Acwing 4793. 危险程度 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;四&gt; 知识风暴 1、排序不等式 2、贪心法 3、数据范围 4、并查集 基本操作
83 0