太空飞行计划问题 网络流24题(2/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行是仪器编号;最后一行是净收益。

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
n,m<=50
思路:
最大闭权子图
最大收益为正权值和-最小割
参考文章最大闭权子图
这道题还需要你输出方案,所以看层数dis[]是否最后有没有跑到,因为要盈利肯定是流没跑满的的边

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=10005;
int n,m,ss,tt;
int dis[N];
int cur[N];
queue<int> q;

struct Edge{int to;int value;int next;}e[N*4];
int head[N],cnt=-1;
void add(int from,int to,int value)
{
    cnt++;
    e[cnt].to=to;
    e[cnt].value=value;
    e[cnt].next=head[from];
    head[from]=cnt;
}

bool bfs(int s,int t)
{
    q=queue<int>();
    memset(dis,-1,sizeof(dis));
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int now=e[i].to;
            if(dis[now]==-1&&e[i].value!=0)
            {
                dis[now]=dis[x]+1;
                q.push(now);
            }
        }
    }
    return dis[t]!=-1;
}

int dfs(int x,int t,int maxflow)
{
    if(x==t)return maxflow;
    int ans=0;
    for(int i=cur[x];i!=-1;i=e[i].next)
    {
        int now=e[i].to;
        if(dis[now]!=dis[x]+1||e[i].value==0||ans>=maxflow)continue;
        cur[x]=i;
        int f=dfs(now,t,min(e[i].value,maxflow-ans));
        e[i].value-=f;
        e[i^1].value+=f;
        ans+=f;
    }
    return ans;
}
int Dinic(int s,int t)
{
    int ans=0;
    while(bfs(s,t))
    {
        memcpy(cur,head,sizeof(head));
        ans+=dfs(s,t,INF);
    }
    return ans;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    int ans=0;
    ss=0,tt=n+m+1;
    for(int i=1;i<=n;i++)
    {
        int c=0;
        scanf("%d",&c);
        ans+=c;
        add(ss,i,c);
        add(i,ss,0);
        while(true)
        {
            char ch=getchar(); if(ch=='\n'||ch=='\r') break;
            int x;
            scanf("%d",&x);
            add(i,n+x,INF);
            add(n+x,i,0);
        }
    }
    for(int i=1;i<=m;i++)
    {
     	int c;
        scanf("%d",&c);
        add(n+i,tt,c);
        add(tt,n+i,0);
    }
    //cout<<ans<<' '<<Dinic(ss,tt)<<endl;
    //return 0;
    ans-=Dinic(ss,tt);
    for(int i=1;i<=n;i++)
	if(dis[i]!=-1) printf("%d ",i);
    printf("\n");
    for(int i=1;i<=m;i++)
	if(dis[i+n]!=-1) printf("%d ",i);
    printf("\n");
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值