POJ 2987 Firing【最大权闭合图】

题意:给定带点权的有向无环图,求最大权闭合图权值,同时要使得选取的点数最小

分析: 建图:

    建立源点 s=0,

         在 s 和 正权点之间连一条边权为该点值的边

         建立汇点 t=n+1

         在 负权点 和 t 之间连一条边权点为该点的绝对值的边

         输入的边权值设为INF,求最大流,

        求最大流后,在残留网络中从s出发dfs能搜到点都为最大权闭合图中的点,

        即这个最小割对应的是最大权闭合图然后让正权点值的累加和减去最大流

        就是闭合图的最大权。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
const int INF=0x1f1f1f1f;
const int maxn=100005;
struct node
{
    int c,next,to;
}e[100000000];
int tot;
int head[maxn];
void add(int s,int u,int flow)
{
    e[tot].to=u;
    e[tot].c=flow;
    e[tot].next=head[s];
    head[s]=tot++;

    e[tot].to=s;
    e[tot].c=0;
    e[tot].next=head[u];
    head[u]=tot++;
}
long long max_flow(int st,int end,int n)
{
    int numh[maxn],h[maxn],curedge[maxn],pre[maxn];
    int cur_flow,u,tmp,neck,i;
    long long maxflow=0;
    clr(h);   clr(numh);
    memset(pre,0xff,sizeof(pre));
    for(i=0;i<=n;i++)
        curedge[i]=head[i];
    numh[0]=n+1;
    u=st;
    while(h[st]<n+1)
    {
        if(u==end)
        {
            cur_flow=INF;
            for(i=st;i!=end;i=e[curedge[i]].to)
                if(cur_flow>e[curedge[i]].c)
                {
                    neck=i;
                    cur_flow=e[curedge[i]].c;
                }
            for(i=st;i!=end;i=e[curedge[i]].to)
            {
                tmp=curedge[i];
                e[tmp].c-=cur_flow;
                e[tmp^1].c+=cur_flow;
            }
            maxflow+=cur_flow;
            u=neck;
        }
        for(i=curedge[u];i!=-1;i=e[i].next)
            if(e[i].c&&h[u]==h[e[i].to]+1)
                break;
        if(i!=-1)
        {
            curedge[u]=i;
            pre[e[i].to]=u;
            u=e[i].to;
        }
        else
        {
            if(--numh[h[u]]==0) break;
            curedge[u]=head[u];
            for(tmp=n,i=head[u];i!=-1;i=e[i].next)
                if(e[i].c)
                    tmp=min(tmp,h[e[i].to]);
            h[u]=tmp+1;
            ++numh[h[u]];
            if(u!=st)
                u=pre[u];
        }
    }
    return maxflow;
}
bool vis[maxn];
void dfs(int u,int t)
{
    int i;
    if(u==t)
        return ;
    vis[u]=true;
    for(i=head[u];i!=-1;i=e[i].next)
        if(e[i].c>0&&!vis[e[i].to])
                dfs(e[i].to,t);
}
int main()
{
    int a,b,w,i,n,m,res;
    long long flow;
    scanf("%d%d",&n,&m);
    long long sum=0;
    int s=0,t=n+1;
    tot=0;
    memset(head,-1,sizeof(head));
    for(i=1;i<=n;i++)
    {
        scanf("%d",&w);
        if(w>0)
        {
            sum+=w;
            add(s,i,w);
        }
        else add(i,t,-w);
    }
    while(m--)
    {
        scanf("%d%d",&a,&b);
        add(a,b,INF);
    }
    flow=max_flow(s,t,n+1);
    clr(vis);
    dfs(s,t);
    res=0;
    for(i=1;i<=n;i++)
        if(vis[i])
            res++;
    printf("%d %lld\n",res,sum-flow);
    return 0;
}

 

posted @ 2012-08-21 00:22  'wind  阅读(200)  评论(0编辑  收藏  举报