cogs727. [网络流24题] 太空飞行计划

介绍一种用于规划太空飞行实验以最大化净收益的有效算法。通过合理选择实验和配置所需仪器,确保收益超过成本。
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={ I1I2,…,I}。实验E需要用到的仪器是I的子集RjI。配置仪器I的费用为c美元。实验E的赞助商已同意为该实验结果支付p美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
【编程任务】
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
【数据输入】
第1行有2个正整数m和n(m,n <= 100)。m是实验数,n是仪器数。接下来的m行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
【结果输出】
第1行是实验编号;第2行是仪器编号;最后一行是净收益。
【输入文件示例】shuttle.in
2 3
10 1 2
25 2 3
5 6 7
【输出文件示例】shuttle.out
1 2
1 2 3
17
求最大权闭合图 详解见胡伯涛论文《最小割模型在信息学竞赛中的应用》
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;

const int inf = 0x3f3f3f3f;

int ans;
int sum;
int n,m;
int tot = 1;
int c[147];
int head[147],nxt[1147],to[1147],wei[1147];
int text[147][147];
bool used[147];
string str;
stringstream ss;
int que[147]; 

void add(int,int,int);
bool bfs();
int dinic(int,int);

int main(){

    freopen("shuttle.in","r",stdin);
    freopen("shuttle.out","w",stdout);

    int a;
    scanf("%d %d",&n,&m);
    getline(cin,str);
    for(int i=1;i<=n;++i){
        ss.clear();
        getline(cin,str);
        ss << str;
        ss >> a;
        add(1,i+1,a);
        sum += a;
        while(ss >> a){
            text[i][++text[i][0]] = a;
            add(i+1,n+1+a,inf);
        }
    }
    for(int i=1;i<=m;++i){
        scanf("%d",&a);
        add(n+1+i,n+m+2,a);
    }

    int flag;
    while(bfs()){
        flag = 1;
        while(flag){
            flag = dinic(1,inf);
            ans += flag;
        }
    }

    for(int i=2;i<=n+1;++i)
        if(c[i]){
            printf("%d ",i-1);
            for(int j=1;j<=text[i-1][0];++j)
                used[text[i-1][j]] = true;
            }
    putchar(10);
    for(int i=1;i<=m;++i)
        if(used[i])
            printf("%d ",i);
    putchar(10);
    printf("%d",sum-ans);

    return 0;

}

void add(int from,int tp,int value){

    ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=value;
    ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0;

}

bool bfs(){

    memset(c,0,sizeof c);
    c[1] = 1;
    int now;
    int H=0,T=1;
    que[1] = 1;

    do{
        now = que[++H];
        for(int i=head[now];i;i=nxt[i])
            if(!c[to[i]] && wei[i]){
                c[to[i]] = c[now]+1;
                que[++T] = to[i];
            }

    }while(H < T);

    return c[n+m+2];

}

int dinic(int place,int low){

    if(place == n+m+2)
        return low;

    int lower;
    for(int i=head[place];i;i=nxt[i])
        if(c[to[i]]==c[place]+1 && wei[i]){
            lower = dinic(to[i],min(low,wei[i]));
            if(lower){
                wei[i] -= lower;
                wei[i^1] += lower;
                return lower;
            }
        }

    return false;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值