版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}