您的位置:首页 > 其它

bzoj 1497 NOI2006最大获利

2016-12-20 21:30 288 查看
我对题意的理解:给出一堆公司和一堆用户,我们买公司需要花钱,每个用户会支付报酬当且仅当他所钟爱的两个公司我都买了,问最大获利

最大权闭合子图= =好厉害的样子 首先我们连边最小割ans 答案就是sum-ans 这个可以想,sum表示在不需要支出的情况下的获利,现在我们需要支出,所以要跑一遍最小割。感觉就是 我们挣的钱可以通过一个途径跑掉,就挣不到,但是一个途径跑掉的钱是有限的。(怎么会有我这么愚蠢的理解呢) 建立源S,汇T 然后由S向所有用户连长度为报酬的边,用户向喜欢的公司连inf(表示一些疯狂的女人为了买衣服会花好多好多钱),然后公司向汇点连长度为价格的边。看着好奇怪啊,但是我想明白啦!

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
# define inf 1e9
using namespace std;
const int maxn=600000;
struct node{int to,next,len;}table[maxn<<2];
int tot=1,head[maxn];
void add(int a,int b,int c)
{
table[++tot]=(node){b,head[a],c};
head[a]=tot;
table[++tot]=(node){a,head[b],0};
head[b]=tot;
}
int n,m,S,T,a[maxn],ans,sum;
int q[maxn],h,t,d[maxn];
bool bfs()
{
h=t=0;
memset(d,0,sizeof d);
q[++t]=S; d[S]=1;
while(h!=t)
{
int x=q[++h];
for(int i=head[x];i;i=table[i].next)
if(!d[table[i].to]&&table[i].len)
{
d[table[i].to]=d[x]+1;
q[++t]=table[i].to;
}
}
return !!d[T];
}
int dfs(int x,int f)
{
if(x==T||!f) return f;
int cnt=0;
for(int i=head[x];i;i=table[i].next)
if(d[table[i].to]==d[x]+1)
{
int hh=dfs(table[i].to,min(f,table[i].len));
table[i].len-=hh;
table[i^1].len+=hh;
cnt+=hh;
f-=hh;
if(!f) break;
}
return cnt;
}
int main()
{
scanf("%d%d",&n,&m);
S=n+m+1,T=n+m+2;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add(m+i,T,a[i]);
}
int a,b,c;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c); sum+=c;
add(S,i,c);
add(i,m+a,inf);
add(i,m+b,inf);
}
while(bfs()) ans+=dfs(S,inf);
cout<<sum-ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息