POJ 2152 Destroying The Graph【最小点权覆盖+最小割】

题意: 有一个有 N 个节点M 条边的的有向图,每个点对应两种操作:

          将该点所有入边删除 ‘+’ ,对应一个花费,将该点所有出边删除 ‘ - ’亦对应一个花费

          问如何操作将所有边删除使得花费的总和最小。

分析:  建图:

           将每个点拆分成两个点, i(左点) 和 i+n(右点) ,

           建立一个源点 s=0,汇点 u=2*n+1

           在源点和每个点左面的点连一条边,容量为删除出边的费用

           在汇点和每个点右面的点连一条边,容量为删除入边的费用

           如果有 u 到 v 的边,在u 和 v +n 之间连一条边,容量为无穷大

           求出最大流即最小割

           从源点深搜找出残流不为 0 的点,把这些点标记掉,剩下的为标记的点即为删除的顶点。

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define INF 0x1f1f1f1f
#define min(a,b)(a)<(b)?(a):(b)
#define clr(x)memset(x,0,sizeof(x))
#define maxn 210
struct node
{
    int c,next,to;
}e[100000];
int tot;
int head[maxn];
void add(int s,int t,int flow)
{
    e[tot].to=t;
    e[tot].c=flow;
    e[tot].next=head[s];
    head[s]=tot++;
}
int max_flow(int st,int end,int n)
{
    int numh[maxn],h[maxn],edge[maxn],pre[maxn];
    int cur_flow,maxflow=0,u,tmp,neck,i;
    clr(h);  clr(numh);
    memset(pre,0xff,sizeof(pre));
    for(i=0;i<=n;i++)
        edge[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[edge[i]].to)
                if(cur_flow>e[edge[i]].c)
                {
                    neck=i;
                    cur_flow=e[edge[i]].c;
                }
            for(i=st;i!=end;i=e[edge[i]].to)
            {
                tmp=edge[i];
                e[tmp].c-=cur_flow;
                e[tmp^1].c+=cur_flow;
            }
            maxflow+=cur_flow;
            u=neck;
        }
        for(i=edge[u];i!=-1;i=e[i].next)
            if(e[i].c&&h[u]==h[e[i].to]+1)
                break;
        if(i!=-1)
        {
            edge[u]=i;
            pre[e[i].to]=u;
            u=e[i].to;
        }
        else 
        {
            if(--numh[h[u]]==0)
                break;
            edge[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;
}
int v[maxn];
void dfs(int r)
{
    v[r]=1;
    int i,k;
    for(i=head[r];i!=-1;i=e[i].next)
    {
        k=e[i].to;
        if(!v[k]&&e[i].c)
        {
            v[k]=1;
            dfs(k);
        }
    }
}
int main()
{
    int i,n,m,s,u,p,a,b,res,num;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        s=0;
        u=2*n+1;
        memset(head,0xff,sizeof(head));
        tot=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&p);
            add(i+n,u,p);
            add(u,i+n,0);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&p);
            add(s,i,p);
            add(i,s,0);
        }
        while(m--)
        {
            scanf("%d%d",&a,&b);
            add(a,b+n,INF);
            add(b+n,a,0);
        }
        res=max_flow(s,u,n*2+1);
        num=0;
        clr(v);
        dfs(s);
        for(i=1;i<=n;i++)
        {
            if(!v[i])
                num++;
            if(v[i+n])
                num++;
        }
        printf("%d\n%d\n",res,num);
        for(i=1;i<=n;i++)
        {
            if(!v[i])
                printf("%d -\n",i);
            if(v[i+n])
                printf("%d +\n",i);
        }
    }
    return 0;
}

 

posted @ 2012-08-11 19:05  'wind  阅读(268)  评论(0编辑  收藏  举报