bzoj1497: [NOI2006]最大获利 最大权闭合子图
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
题解:最大权闭合子图,对于一个有向图来说,每个节点有权值(可正可负),求找一张子图满足点权和最大,对于一条边u->v来说,如果u被选中了,那么v也要被选中,可以转化成最小割模型,点权和最大即正点权-最小割,最小割是s想正点权点连一条容量为点权的边,负点权点连一条容量为负点权的边,原图中的边容量为inf,那么对于这题来说只需要把边也看成点,跑一遍最小割即可
/**************************************************************
Problem: 1497
User: walfy
Language: C++
Result: Accepted
Time:2172 ms
Memory:25288 kb
****************************************************************/
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define ld long double
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
const double eps=1e-6;
const int N=55000+10,maxn=2000000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
struct edge{
int to,Next,c;
}e[maxn];
int s,t,cnt,head[N];
void init()
{
cnt=0;
memset(head,-1,sizeof head);
}
void add(int u,int v,int c)
{
e[cnt].to=v;
e[cnt].c=c;
e[cnt].Next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].c=0;
e[cnt].Next=head[v];
head[v]=cnt++;
}
int dis[N];
bool bfs()
{
queue<int>q;
memset(dis,-1,sizeof dis);
dis[s]=1;
q.push(s);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=head[x];~i;i=e[i].Next)
{
int y=e[i].to;
if(dis[y]==-1&&e[i].c>0)
{
dis[y]=dis[x]+1;
q.push(y);
}
}
}
return dis[t]!=-1;
}
int dfs(int u,int mx)
{
if(u==t)return mx;
int flow=0,f;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
if(dis[x]==dis[u]+1&&e[i].c>0&&(f=dfs(x,min(mx-flow,e[i].c))))
{
e[i].c-=f;
e[i^1].c+=f;
flow+=f;
}
}
if(flow==0)dis[u]=-2;
return flow;
}
int maxflow()
{
int ans=0,f;
while(bfs())
{
while((f=dfs(s,inf)))ans+=f;
}
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
s=n+m+1,t=n+m+2;
init();
int ans=0;
for(int i=1;i<=n;i++)
{
int c;
scanf("%d",&c);
add(i,t,c);
}
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);ans+=c;
add(i+n,a,inf);
add(i+n,b,inf);
add(s,i+n,c);
}
printf("%d\n",ans-maxflow());
return 0;
}
/********************
********************/