您的位置:首页 > 其它

hdu 3879 Base Station (最大权闭合图)

2013-10-21 20:31 369 查看
结论:正的权值的和-建图后的最小割的容量

选择了一条边就会选择两个点,边的花费为正,点的花费为负,把边看成点,这个点向两个端点连一条边,表示选择这条边就会选择这两个点

然后题目就相当于最大权闭合图的模型了

题意:有n个点,m个选择,建造n个点各自需要一定花费,每个选择有一定的获利,会选择两个点,当然也要花费

求最大的获利

每个选择看成是获利点,每个点看成是花费点,新建源点向获利点建边,权值为获利的大小,花费点向汇点建边,权值为花费的大小

每个选择向相应的两个点连一条容量为无穷大的边,然后求网络的最小割

答案就为正的权值和-最小割的容量

最小割肯定为简单割(直接与源点或汇点相连),在这个题目中

如果与汇点相连的边为割边,表示这个点没有被选择来建station

如果与源点相连的边为割边,表示不选择某个客户的要求来连接某两个station

所以可以理解成:最终收益= 所有可能收益-(损失的收益+架设费用)括号中的即为最小割所求



//要加反向边模板

#include<iostream>

#include<stdio.h>

#include<memory.h>

#include<cmath>

using namespace std;

#define MAXN 60000

#define MAXE 1000000

#define inf 1e9-1

int ne,nv,tmp,s,t,index;

struct Edge{

int next,pair;

int v,cap,fLow;

}edge[MAXE];



int c[5005];

int net[MAXN];

int ISAP()

{

int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];



int cur_fLow,max_fLow,u,tmp,neck,i;

memset(dist,0,sizeof(dist));

memset(numb,0,sizeof(numb));

memset(pre,-1,sizeof(pre));

for(i = 1 ; i <= nv ; ++i)

curedge[i] = net[i];

numb[nv] = nv;

max_fLow = 0;

u = s;

while(dist[s] < nv)

{

if(u == t)

{

cur_fLow = inf;

for(i = s; i != t;i = edge[curedge[i]].v)

{

if(cur_fLow > edge[curedge[i]].cap)

{

neck = i;

cur_fLow = edge[curedge[i]].cap;

}

}

for(i = s; i != t; i = edge[curedge[i]].v)

{

tmp = curedge[i];

edge[tmp].cap -= cur_fLow;

edge[tmp].fLow += cur_fLow;

tmp = edge[tmp].pair;

edge[tmp].cap += cur_fLow;

edge[tmp].fLow -= cur_fLow;

}

max_fLow += cur_fLow;

u = neck;

}

/* if .... eLse ... */

for(i = curedge[u]; i != -1; i = edge[i].next)

if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)

break;

if(i != -1)

{

curedge[u] = i;

pre[edge[i].v] = u;

u = edge[i].v;

}else{

if(0 == --numb[dist[u]]) break;

curedge[u] = net[u];

for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)

if(edge[i].cap > 0)

tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];

dist[u] = tmp + 1;

++numb[dist[u]];

if(u != s) u = pre[u];

}

}

return max_fLow;

}

void add(int u,int v,int f)

{

edge[index].next = net[u];

edge[index].v = v;

edge[index].cap = f;

edge[index].fLow = 0;

edge[index].pair = index+1;

net[u] = index++;

edge[index].next = net[v];

edge[index].v = u;

edge[index].cap = 0;

edge[index].fLow = 0;

edge[index].pair = index-1;

net[v] = index++;



}

int main()

{

int n,m,a,b,c,x;

while(~scanf("%d%d",&n,&m))

{

index=0;

memset(net,-1,sizeof(net));

for(int i = 1 ; i <= n ; i++)

{

scanf("%d",&x);

add(i,n+m+1,x); //连汇点

}

int sum =0 ;

for(int i = 1 ; i <= m ; i++)

{

scanf("%d%d%d",&a,&b,&c);

add(0,i+n,c); //连源点

add(i+n,a,inf); //边这个点,连两端点

add(i+n,b,inf);

sum += c ;

}

s=0;t=n+m+1;nv=t+1;

printf("%d\n",sum-ISAP());

}

return 0;

}



//sap模板(建图简单点)

#include<cstdio>

#include<cstring>

#include<map>

#include<vector>

#include<cmath>

#include<cstdlib>

#include<stack>

#include<queue>

#include <iomanip>

#include<iostream>

#include<algorithm>

using namespace std ;

const int N=60000;

const int M=1000000 ;

const int inf=1000000000;

struct node

{

int u , v, next ,c ;

}edge[M];

int pre
,head
,gap
,dis
,cur
;

int s,t,top,NV;

void add(int u, int v , int c)

{

edge[top].u=u;

edge[top].v=v;

edge[top].c=c;

edge[top].next=head[u];

head[u]=top++;



edge[top].u=v;

edge[top].v=u;

edge[top].c=0;

edge[top].next=head[v];

head[v]=top++;

}

int sap()

{

memset(dis,0,sizeof(dis));

memset(gap,0,sizeof(gap));

for(int i = 0 ; i < NV ; ++i)

cur[i] = head[i];

int u = pre[s] = s,maxflow = 0,aug = inf;

gap[0] = NV;

while(dis[s] < NV)

{

loop:

for(int &i = cur[u]; i != -1; i = edge[i].next)

{

int v = edge[i].v;

if(edge[i].c && dis[u] == dis[v] + 1)

{

aug=min(aug,edge[i].c);

pre[v] = u;

u = v;

if(v == t)

{

maxflow += aug;

for(u = pre[u]; v != s; v = u,u = pre[u])

{

edge[cur[u]].c -= aug;

edge[cur[u]^1].c += aug;

}

aug =inf;

}

goto loop;

}

}

if( (--gap[dis[u]]) == 0) break;

int mindis = NV;

for(int i = head[u]; i != -1 ; i = edge[i].next)

{

int v = edge[i].v;

if(edge[i].c && mindis > dis[v])

{

cur[u] = i;

mindis = dis[v];

}

}

gap[ dis[u] = mindis+1 ] ++;

u = pre[u];

}

return maxflow;

}

int main()

{

int n,m,a,b,c,x;

while(~scanf("%d%d",&n,&m))

{

top=0;

memset(head,-1,sizeof(head));

for(int i = 1 ; i <= n ; i++)

{

scanf("%d",&x);

add(i,n+m+1,x);

}

int sum =0 ;

for(int i = 1 ; i <= m ; i++)

{

scanf("%d%d%d",&a,&b,&c);

add(0,i+n,c);

add(i+n,a,inf);

add(i+n,b,inf);

sum += c ;

}

s=0;t=n+m+1;NV=t+1;

printf("%d\n",sum-sap());

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: