太空飞行计划问题 网络流24题

题目描述

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行是仪器编号;最后一行是净收益。

思路:首先考虑二分图模型,把实验和仪器分为两个集合,A,B,原点src向A集合建立一条容量为该实验赞助费用的边,汇点sink与B集合之间建立容量为仪器费用的边,而实验和实验所需要的仪器之间建立容量为无穷的边,这里每一种割都是一种方案。我们可以发现这里割的值就等于已经选的仪器的价值+未被选的实验的价值,而我们要求的ans就是所有实验的价值-(已经选的仪器的价值+未被选的实验的价值)=已经选的实验-已经选的仪器,为了让ans最大,我们就让割值最小,这就变成了一个最小割模型。(%%%%%%%)

#include<bits/stdc++.h>
using namespace std;
const int inf=1000000000;
const int maxn=20000,maxm=1e6+10;
struct Edge{
    int v,f,nxt;
};
int src,sink;
int g[maxn+10];
int nume;
Edge e[maxm*2+10];
void addedge(int u,int v,int c) {
    e[++nume].v=v;
    e[nume].f=c;
    e[nume].nxt=g[u];
    g[u]=nume;
    e[++nume].v=u;
    e[nume].f=0;
    e[nume].nxt=g[v];
    g[v]=nume;
}
void init() {
    memset(g,0,sizeof(g));
    nume=1;
}
queue<int> que;
bool vis[maxn+10];
int dist[maxn+10];
int n,m,k,dfn;
int h[maxn];
int a[maxn][30];
bool bfs() {
    memset(dist,0,sizeof(dist));
    while(!que.empty())que.pop();
    vis[src]=true;
    que.push(src);
    while(!que.empty()) {
        int u=que.front();
        que.pop();
        for(int i=g[u];i;i=e[i].nxt) {
            if(e[i].f && !vis[e[i].v]) {
                que.push(e[i].v);
                dist[e[i].v]=dist[u]+1;
                vis[e[i].v]=true;
            }
        }
    }
    return vis[sink];
}
int dfs(int u,int delta) {
    if(u==sink) {
        return delta;
    }
    else {
        int ret=0;
        for(int i=g[u];delta&&i;i=e[i].nxt) {
            if(e[i].f && dist[e[i].v]==dist[u]+1) {
                int dd=dfs(e[i].v,min(e[i].f,delta));
                e[i].f-=dd;
                e[i^1].f+=dd;
                delta-=dd;
                ret+=dd;
            }
        }
        return ret;
    }
}
int maxflow() {
    int ret=0;
    while(true) {
        memset(vis,0,sizeof(vis));
        bfs();
        if(!vis[sink]) return ret;
        ret+=dfs(src,inf);
    }
}
char c[maxn];
int to[maxn];
int in[maxn];
int val[maxn];
int main() {
    init();
    scanf("%d%d",&n,&m);
    src=0;
    sink=n+m+1;
    int ans=0;
    /**for(int i=1;i<=n;i++) {
        int u,v,l;
        scanf("%d%d%d",&u,&v,&l);
        addedge(src,i,u);
        addedge(i,n+v,inf);
        addedge(i,n+l,inf);
        ans+=u;
    }*/

    /**for (int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        ans+=val[i];
        addedge(src,i,val[i]);
        memset(c,0,sizeof(c));
        cin.getline(c,10000);
        int ulen=0;
        int num;
        while (sscanf(c+ulen,"%d",&num)==1)
        {
            ///req[i].pb(num);
            addedge(i,n+num,inf);
            if (num==0) ulen++;
            else while (num)
            {
                num/=10;
                ulen++;
            }
            ulen++;
        }
    }*/
    for(int i=1;i<=m;i++) {
        scanf("%d",&in[i]);
    }
    for(int i=1;i<=m;i++) {
        addedge(n+i,sink,in[i]);
    }
    ans=ans-maxflow();
    for(int i=1;i<=n;i++) {
        if(vis[i]) printf("%d ",i);
    }
    puts("");
    for(int i=1;i<=m;i++) {
        if(vis[i+n]) printf("%d ",i);
    }
    puts("");
    printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值