洛谷 P 2762

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84869737

这道题还是网络流。

目前知道了实验花费,设备花费,知道了赞助金。

我们的目的是骗取最多的赞助金,那么这个技巧就在于如何选实验和器材了,如果实验都能做,器材都不花钱,那么我们肯定把所有实验都做掉就会赚的钱更多,那么一涉及到选择什么东西。。立刻就想到了割这个东西,那么我们要选取的肯定是最小的割,来保证我们选的钱是最少的,那么我们建图的时候就有思路了()

( S )-------赞助金----- (实验) -----INF------( 器材 )---设备花费--- (T)

那么最大利益  = 总利益 - 不做的实验赞助 - 做的实验花费

那么我们想一下为什么会有不做的实验呢?很显然这个实验是亏本的,所以我们不去搞他,所以我们在割边的时候也会顺路把这个实验资金割掉,这样就很巧妙了,我们只要用 总利益减去 最小割(最大流)得出的就是最大利益。

所以建个图,跑一次最大流,最后再看看一那些边是没被我们割掉的,就是代表我们选择的,最后输出相应的实验和器材。

扫描二维码关注公众号,回复: 4491798 查看本文章

以下是AC 代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1e6+5;
const int INF = 0x3f3f3f3f;
int head[maxn],tot = 1;
int val[maxn];
struct node
{
    int to;
    int nxt;
    int val;
}ed[maxn];
void add(int u,int v,int w)
{
    ed[++tot].to = v, ed[tot].val = w, ed[tot].nxt = head[u], head[u] = tot;
    ed[++tot].to = u, ed[tot].val = 0, ed[tot].nxt = head[v], head[v] = tot;
}
int h[maxn];
int s,t,m,n;
bool bfs()
{
    memset(h,0,sizeof h);
    h[s] = 1;
    queue<int>q;
    q.push(s);
    while(q.size())
    {
        int u = q.front();
        q.pop();
        for(int i=head[u]; ~i; i=ed[i].nxt)
        {
            int v = ed[i].to;
            if(h[v] == 0 && ed[i].val > 0)
            {
                h[v] = h[u] + 1;
                q.push(v);
                if(v == t)
                    return true;
            }
        }
    }
    return h[t];
}
int dfs(int u,int val)
{
    if(u == t)
        return val;
    int ans = 0;
    for(int i=head[u]; ~i; i=ed[i].nxt)
    {
        int v = ed[i].to;
        if(ed[i].val && h[v] == h[u] + 1)
        {
            int res = dfs(v, min(val - ans, ed[i].val));
            ed[i].val -= res;
            ed[i ^ 1].val += res;
            ans += res;
        }
    }
    return ans;
}
int dinic()
{
    int ans = 0;
    while(bfs())
    {
        ans += dfs(s,INF);
    }
    return ans;
}
int main()
{
    scanf("%d%d",&m,&n);
    int sum = 0;
    s = 0, t = n + m + 1;
    memset(head, -1, sizeof head);
    for(int i=1;i<=m;i++)
    {
        int k;
        scanf("%d",&k);
        sum += k;
        add(s, i, k);
        while(getchar()!='\n')
        {
            scanf("%d",&k);
            add(i, k + m, INF);
        }
    }
    for(int i=1;i<=n;i++)
    {
        int k;
        scanf("%d",&k);
        add(i + m, t, k);
    }
    int cnt = dinic();
    for(int i=1; i<=m; i++)
    {
        if(h[i] > 0)
            printf("%d ",i);
    }
    printf("\n");
    for(int i=1+m; i<=m+n; i++)
    {
        if(h[i] > 0)
            printf("%d ", i - m);
    }
    printf("\n");
    printf("%d\n",sum - cnt);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/84869737