最大权闭合图hdu3996
定义:最大权闭合图:是有向图的一个点集,且该点集的所有出边都指向该集合。即闭合图内任意点的集合也在改闭合图内,给每个点分配一个点权值Pu,最大权闭合图就是使闭合图的点权之和最大。
最小割建边方式:源点s和正权的点连接,容量是Pu,负权的点和汇点t相连,容量是-Pu,之间的边权值inf,过一遍最大流ans,正权之和sum-ans就是最大权闭合图的值。
例题:HDU3996
题意:给出n个金矿地区,每个金矿地区有mi个矿坑,挖取第i个地区的第j个矿坑需要花费cost[i][j],可以获得利益value[i][j],但是有些限制条件,就是想要挖取第i个地区的第j个矿坑之前必须把第ii个地区的第jj个矿坑挖掉.问最大获益是多少?
分析:共用n*Mi个矿坑,每个点的权值是value[i][j]-cost[i][j],建边从第i,j指向ii,jj,表示要选取i,j一定会选取ii,jj。建边后跑一遍Dinic即可。
#include"stdio.h" #include"string.h" #include"stdlib.h" #include"algorithm" #include"math.h" #include"vector" #include"queue" #define M 3009 #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[M*300]; int t,head[M],dis[M]; int lay[M],num[111][30],work[M]; LL p[M],cost[M]; 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; st(int uu,int vv) { u=uu; v=vv; } }; vector<st>s[M]; int main() { int Case,n,i,j,k,K,ii,jj,kk=1; scanf("%d",&Case); while(Case--) { scanf("%d",&n); for(i=1;i<M;i++) s[i].clear(); int cnt=0; init(); for(i=1;i<=n;i++) { scanf("%d",&lay[i]); for(j=1;j<=lay[i];j++) { num[i][j]=++cnt; scanf("%I64d%I64d%d",&cost[cnt],&p[cnt],&K); for(k=1;k<=K;k++) { scanf("%d%d",&ii,&jj); s[cnt].push_back(st(ii,jj)); } } } init(); for(i=1;i<=n;i++) { for(j=1;j<=lay[i];j++) { for(k=0;k<(int)s[num[i][j]].size();k++) { int ii=s[num[i][j]][k].u; int jj=s[num[i][j]][k].v; add(num[i][j],num[ii][jj],inf); } } } LL sum=0; for(i=1;i<=cnt;i++) { if(p[i]-cost[i]>0) { add(0,i,p[i]-cost[i]); sum+=p[i]-cost[i]; } else if(p[i]-cost[i]<0) add(i,cnt+1,cost[i]-p[i]); } LL ans=Dinic(0,cnt+1); printf("Case #%d: ",kk++); printf("%d\n",sum-ans); } return 0; }