最大权闭合图最大获益(把边抽象为点)HDU3879
题意:给出一个无向图,每个点都有点权值代表花费,每条边都有利益值,代表形成这条边就可以获得e[i]的利益,问选择那些点可以获得最大利益是多少?
分析:把边抽象成点,s与该点建边,容量是利益值,每个点与t建边,容量是花费值,然后抽象出来的点分别和对于的边的两个端点连边,权值是inf;代表只要选择该边就一定要选择两个端点,这就转化为了最大权闭合图
程序:
#include"stdio.h" #include"string.h" #include"stdlib.h" #include"algorithm" #include"math.h" #include"vector" #include"queue" #define Maxn 60009 #define Maxm 400009 #define inf 1000000000000000LL #define eps 1e-7 #define pps 1e-18 #define PI acos(-1.0) #define LL __int64 using namespace std; struct node { int u,v,next; LL w; }edge[Maxm]; int t,head[Maxn],work[Maxn],dis[Maxn]; LL cost[Maxn]; LL min(LL a,LL b) { return a<b?a:b; } void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,LL w) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].next=head[u]; head[u]=t++; edge[t].u=v; edge[t].v=u; edge[t].w=0; edge[t].next=head[v]; head[v]=t++; } int bfs(int S,int T) { queue<int>q; memset(dis,-1,sizeof(dis)); q.push(S); dis[S]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]==-1) { dis[v]=dis[u]+1; if(v==T) return 1; q.push(v); } } } return 0; } LL dfs(int cur,LL a,int T) { if(cur==T)return a; for(int &i=work[cur];~i;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]==dis[cur]+1) { LL tt=dfs(v,min(a,edge[i].w),T); if(tt) { edge[i].w-=tt; edge[i^1].w+=tt; return tt; } } } return 0; } LL Dinic(int S,int T) { LL ans=0; while(bfs(S,T)) { memcpy(work,head,sizeof(head)); while(LL tt=dfs(S,inf,T)) ans+=tt; } return ans; } struct st { int u,v; LL value; }e[Maxm]; int main() { int n,m,i; while(scanf("%d%d",&n,&m)!=-1) { for(i=1;i<=n;i++) scanf("%I64d",&cost[i]); LL sum=0; for(i=1;i<=m;i++) { scanf("%d%d%I64d",&e[i].u,&e[i].v,&e[i].value); sum+=e[i].value; } init(); for(i=1;i<=m;i++) { add(0,i,e[i].value); add(i,m+e[i].u,inf); add(i,m+e[i].v,inf); } for(i=1;i<=n;i++) add(i+m,m+n+1,cost[i]); LL ans=Dinic(0,m+n+1); printf("%I64d\n",sum-ans); } return 0; }