poj 2987 最大权闭合图
由上一篇可得
最大权闭合图的权值为sum-max_flow
sum为正的权值和,max_flow为重新建图后的最大流
求最大流后,在残留网络中从s出发dfs能搜到点都为最大权闭合图中的点,即这个最小割对应的是最大权闭合图
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<string.h>
const int MAX=100005;
const int INF=1000000000;
struct
{
int v,c,next;
}edge[1000000];
int E,head[MAX];
int gap[MAX],cur[MAX];
int pre[MAX],dis[MAX];
void add_edge(int s,int t,int c,int cc)
{
/*加边的时候同时加两条,
一条正的,一条反的,
一般情况下反的容量是0 */
edge[E].v=t; edge[E].c=c;
edge[E].next=head[s];
head[s]=E++;
edge[E].v=s; edge[E].c=cc;
edge[E].next=head[t];
head[t]=E++;
}
int min(int a,int b){return (a==-1||b<a)?b:a;}
__int64 SAP(int s,int t,int n)
{
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
int i;
for(i=0;i<n;i++)cur[i]=head[i];
int u=pre[s]=s,aug=-1,v;
__int64 maxflow=0;
gap[0]=n;
while(dis[s]<n)
{
loop: for(i=cur[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[u]==dis[v]+1)
{
aug=min(aug,edge[i].c);
pre[v]=u;
cur[u]=i;
u=v;
if(u==t)
{
for(u=pre[u];v!=s;v=u,u=pre[u])
{
edge[cur[u]].c-=aug;
edge[cur[u]^1].c+=aug;
}
maxflow+=aug;
aug=-1;
}
goto loop;
}
}
int mindis=n;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0&&dis[v]<mindis)
{
cur[u]=i;
mindis=dis[v];
}
}
if((--gap[dis[u]])==0)break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return maxflow;
}
bool vis[MAX];
void dfs(int u,int t)
{
if(u==t) return ;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next)
if(edge[i].c>0 && !vis[edge[i].v])
dfs(edge[i].v,t);
}
int main()
{
int i,n,m,j,w,a,b;
scanf("%d%d",&n,&m);
__int64 sum=0;
int s=0,t=n+1;
memset(head,-1,sizeof(head)); E=0;
for(i=1;i<=n;i++)
{
scanf("%d",&w);
if(w>0)
{sum+=w;
add_edge(s,i,w,0);
}
else add_edge(i,t,-w,0);
}
while(m--)
{
scanf("%d%d",&a,&b);
add_edge(a,b,INF,0);
}
__int64 mxflow=SAP(s,t,n+2);
memset(vis,0,sizeof(vis));
dfs(s,t);int ans=0;
for(i=1;i<=n;i++)
{
if(vis[i])
ans++;
}
printf("%d %I64d\n",ans,sum-mxflow);
return 0;
}