这道题是个人赛得时候看到的。。但是实在想不出要怎么建图。。最后学长讲了才略懂。。
下面根据学长讲的做下总结:
题意:
公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。
•另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N)
•THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
•本题可以参考:(最大获利)
•:http://judge.noi.cn/problem?id=1142
•在胡伯涛论文 《最小割模型在信息学竞赛中的应用》中有详细介绍过这个问题.
•在论文的第四节中,介绍最大密度子图模型.先将其转化为最大闭合图模型解决,又重新提出了一个用最小割模型解决的新方法很好的解决了"最大获利(profit)问题"
最大权闭合图 Maximum Weight Closure of a Graph
•定义一个有向图G = (V, E)的闭合图是该有向图的一个点集,且该点集的所有出边都还指向该点集。即闭合图内的任意点的任意后继也一定在闭合图中。更形式化地说,闭合图是这样的一个点集V'∈V,满足对于∀u∈V'引出的∀<u, v>∈E,必有v∈V'成立。
闭合图的性质
闭合图的性质有恰好反映了事物间的必要条件的关系,一个事件的发生,它说需要的所有前提也都要发生。这就对应着图里面的所有由u引出的边e,在闭合图里u和由u的出边e到达的点v是一个整体,就是说,如果一个闭合图包含了u,就必须也要包含v,但是如果一个闭合图包含了v,却不一定要包含u,只要利用好这种必要关系,就可以很快建图了。
•将每个用户(m)和中转站(n)看作点,另外添加源点s,汇点t,所以所构图中有(n+m+1+1)个点.
•添加下列边:
•①s到用户i,容量为Ci
•②用户i到中转站Ai和Bi,容量为∞
•③中转站i到t,容量为Pi
•考虑这个模型的割
•割边不可能是②中的边,这保证了解的合法性
•属于①的割边表示损失的利益
•属于③的割边表示付出的代价
• 因为最大获益=用户总获益-未选择用户群应得获益-中转站花费=用户总获益-(未选择用户群应得获益+中转站花费)
•显然割的量越小越好,这样这道题就转换成一个最小割的问题
•根据最大流最小割定理,设sum=∑Ci,我们只要求出该网络的最大流maxflow,则sum-maxflow就是最大获利
•对于这个网络流模型,它的最小割的意义就是未选择用户群应得获益+中转站花费.
•这样,只要求出最小切割,然后用用户总获益减去最小切割就可以了.
•
根据最小割最大流定理,求一个最大流,问题解决. 个人觉得学长的总结非常好。。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 55005 //这个是点集。。不用太大。。
#define M 320005//这个是边集。。要开大一点。。
//实在又不懂这个数组为什么又要开这么大。。
//请教学长也是讲不出所以然来。。但是他教了好方法,,就是题目最大能开多大,就开多大。。
//自己总结也是。。以后如果再这样的话。。就尽量往大了试。。
#define inf 99999999
using namespace std;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 55005 //这个是点集。。不用太大。。
#define M 320005//这个是边集。。要开大一点。。
//实在又不懂这个数组为什么又要开这么大。。
//请教学长也是讲不出所以然来。。但是他教了好方法,,就是题目最大能开多大,就开多大。。
//自己总结也是。。以后如果再这样的话。。就尽量往大了试。。
#define inf 99999999
using namespace std;
int n,m;
int s,t,num,adj[N],dis[N],q[N];
int s,t,num,adj[N],dis[N],q[N];
int min(int a,int b)
{
if(a>b)
return b;
else
return a;
}
{
if(a>b)
return b;
else
return a;
}
struct edge
{
int v,w,pre;
}e[M];
{
int v,w,pre;
}e[M];
void insert(int u,int v,int w)
{
e[num].v=v;
e[num].w=w;
e[num].pre=adj[u];
adj[u]=num++;
e[num].v=u;
e[num].w=0;
e[num].pre=adj[v];
adj[v]=num++;
}
int bfs()
{
int i,x,v,tail=0,head=0;
memset(dis,0,sizeof(dis));
dis[s]=1;
q[tail++]=s;
while(head<tail)
{
x=q[head++];
for(i=adj[x];i!=-1;i=e[i].pre)
if(e[i].w&&dis[v=e[i].v]==0)
{
dis[v]=dis[x]+1;
if(v==t)
return 1;
q[tail++]=v;
}
}
return 0;
}
int dfs(int s,int limit)
{
if(s==t)
return limit;
int i,v,tmp,cost=0;
for(i=adj[s];i!=-1;i=e[i].pre)
if(e[i].w&&dis[s]==dis[v=e[i].v]-1)
{
tmp=dfs(v,min(limit-cost,e[i].w));
if(tmp>0)
{
e[i].w-=tmp;
e[i^1].w+=tmp;
cost+=tmp;
if(limit==cost)
break;
}
else dis[v]=-1;
}
return cost;
}
int Dinic()
{
int ans=0;
while(bfs())
ans+=dfs(s,inf);
return ans;
}
{
e[num].v=v;
e[num].w=w;
e[num].pre=adj[u];
adj[u]=num++;
e[num].v=u;
e[num].w=0;
e[num].pre=adj[v];
adj[v]=num++;
}
int bfs()
{
int i,x,v,tail=0,head=0;
memset(dis,0,sizeof(dis));
dis[s]=1;
q[tail++]=s;
while(head<tail)
{
x=q[head++];
for(i=adj[x];i!=-1;i=e[i].pre)
if(e[i].w&&dis[v=e[i].v]==0)
{
dis[v]=dis[x]+1;
if(v==t)
return 1;
q[tail++]=v;
}
}
return 0;
}
int dfs(int s,int limit)
{
if(s==t)
return limit;
int i,v,tmp,cost=0;
for(i=adj[s];i!=-1;i=e[i].pre)
if(e[i].w&&dis[s]==dis[v=e[i].v]-1)
{
tmp=dfs(v,min(limit-cost,e[i].w));
if(tmp>0)
{
e[i].w-=tmp;
e[i^1].w+=tmp;
cost+=tmp;
if(limit==cost)
break;
}
else dis[v]=-1;
}
return cost;
}
int Dinic()
{
int ans=0;
while(bfs())
ans+=dfs(s,inf);
return ans;
}
int main()
{
int i,p,a,b,c;
int sum;
while(scanf("%d%d",&n,&m)!=EOF)
{
sum=0;
memset(adj,-1,sizeof(adj));//一定要记得初始化。。
num=0;
for(i=1;i<=n;i++)
{
scanf("%d",&p);
insert(i+m,n+m+1,p);
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
insert(0,i,c);
insert(i,a+m,inf);
insert(i,b+m,inf);
sum+=c;
}
s=0;
t=n+m+1;
cout<<sum-Dinic()<<endl;
}
return 0;
}
{
int i,p,a,b,c;
int sum;
while(scanf("%d%d",&n,&m)!=EOF)
{
sum=0;
memset(adj,-1,sizeof(adj));//一定要记得初始化。。
num=0;
for(i=1;i<=n;i++)
{
scanf("%d",&p);
insert(i+m,n+m+1,p);
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
insert(0,i,c);
insert(i,a+m,inf);
insert(i,b+m,inf);
sum+=c;
}
s=0;
t=n+m+1;
cout<<sum-Dinic()<<endl;
}
return 0;
}