洛谷 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;
}

 

目录
相关文章
|
8月前
|
索引
洛谷P1231 教辅的组成
洛谷P1231 教辅的组成
|
9月前
|
机器学习/深度学习
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
《蓝桥杯每日一题》背包dp·AcWing3382. 整数拆分
46 0
洛谷1102 A-B 暴力法
判断第 i 个数和 i 之后的每一个数的绝对值是否等于目标结果
|
机器学习/深度学习 算法 搜索推荐
洛谷每日三题之第六天
洛谷每日三题之第六天
|
机器学习/深度学习 算法 IDE
洛谷每日三题之第四天
洛谷每日三题之第四天
洛谷 P1469 找筷子
题目描述 经过一段时间的紧张筹备,电脑小组的“RP餐厅”终于开业了,这天,经理LXC接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题,筷子!CX小朋友找出了餐厅中所有的筷子,但遗憾的是这些筷子长短不一,而我们都知道筷子需要长度一样的才能组成一双,更麻烦的是CX找出来的这些筷子数量为奇数,但是巧合的是,这些筷子中只有一只筷子是落单的,其余都成双,善良的你,可以帮CX找出这只落单的筷子的长度吗? 输入输出格式 输入格式:   第一行读入一个数N,它代表CX找到的筷子的根数。
1188 0
|
算法
洛谷 P1816 忠诚
题目描述 老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。
1140 0