洛谷_2762 太空飞行计划问题

本文介绍了一种利用最小割算法解决实验收益最大化问题的方法。通过建立一个特殊的流量网络,将实验与所需器材间的依赖关系转化为图中的边,并利用Dinic算法进行求解,最终确定最优的实验组合及所使用的器材。

题意

给出一些实验和器材,每种实验需要一些器材,每种实验如果做了可以获取一定的收益但是要支付实验器材相应的代价。器材如果买过了就不用再买了。现在给出一些实验和器材的收益和价值,求出我们最多能获得多少收益和做了的实验和用了的器材。

思路

收益:先存下实验的一共得收益。我们对一个实验有两种选择:做这个实验,支付器材相应的价值;不做这个实验,减去这个实验可以获得的收益。这样子就变成了求一个图的最小割问题,把实验和源点连一条边,容量为实验的收益,把器材和汇点连一条边,容量为器材代价,实验和器材之间要连一条容量无穷大的边,所以我们不会割这条边。
求做了的实验和器材:在dinic算法中我们会构建分层图,判断实验和器材的深度我们就可以知道有没有做过哪些实验和器材了。

代码

#include<cstdio>
#include<queue>
using namespace std;
int tot,m,n,ans,head[1030],d[1030],f[1030],num,val,S,T,ff;
char c;
struct node{
    int to,flow,next;
}e[26010];
void add(int x,int y,int flow)
{
    e[++tot].to=y;e[tot].flow=flow;e[tot].next=head[x];
    head[x]=tot;
    e[++tot].to=x;e[tot].flow=0;e[tot].next=head[y];
    head[y]=tot;
}
bool bfs()
{
    queue<int> q;
    int x,y;
    for (int i=1;i<=T;i++) d[i]=0;
    q.push(S);d[S]=1;
    while (q.size())
    {
        x=q.front();q.pop();
        for (int i=head[x];i;i=e[i].next)
        {
            y=e[i].to;
            if (e[i].flow&&!d[y])
            {
                d[y]=d[x]+1;
                q.push(y);
                if (y==T) return 1;
            }
        }
    }
    return 0;
}
int dfs(int k,int flow)
{
    if (k==T) return flow;
    int rest=0,w,y;//rest一定要清0 
    for (int i=head[k];i;i=e[i].next)
    {
        y=e[i].to;
        if (e[i].flow&&d[y]==d[k]+1)
        {
            w=dfs(y,min(flow-rest,e[i].flow));
            if (!w) d[y]=0;
            e[i].flow-=w;
            e[i^1].flow+=w;
            rest+=w;
        }
    }
    return rest;
}
int main()
{
    scanf("%d%d",&m,&n);
    tot=1;S=0;T=m+n+1;
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&f[i]);
        ans+=f[i];
        add(S,i,f[i]);
        scanf("%c",&c);
        num=0;
        while ((scanf("%c",&c)),c!='\n')
        {
            if (c>='0'&&c<='9') num=num*10+c-48;
            else add(i,num+m,2147483647),num=0;
        }
        add(i,num+m,2147483647);
    }
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&val);
        add(i+m,T,val);
    }
    while (bfs())
        while (ff=dfs(S,2147483647)) ans-=ff;//最大收益
    for (int i=1;i<=m;i++)
        if (d[i]) printf("%d ",i);//求做了的实验
    printf("\n");
    for (int i=m+1;i<=n+m;i++)
        if (d[i]) printf("%d ",i-m);//求用过了的器材
    printf("\n");
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值