poj2125 最小点权覆盖集

 题意:有一张图,对于每个点,有出边和入边,现在目的是删除改图的所有边,对于每个点,删除出边的花费Wi-,删除入边的花费Wi+,现在的目的求删去所有边后的花费最小。

建图方法:对于每个点i,拆点为i,i+n,对于入边,从i+n想汇点T连边,值为入边花费;对于出边,从S向i连边,权值为出边花费。m组相连的边(x,y),从x向y+n连边, 费用INF。求出最小割。

然后是计算删除的是哪些点。对于完成最小割后的图,从源点S进行dfs,如果能够访问到,标记。对于不能访问到的点,i<=n时,这个点的出边是属于割集的,即所求点,且为‘-’;如果i>n,表示该点为需要删除的边的点,为'+';

最小割后的图片

(ps:S,T写错了。。。)

根据图很明显的可以看出哪些边时需要删除,并且是哪些点的边。

#include<stdio.h>
#include<string.h>
#include<queue>
#define INF 99999999
using namespace std;
const int maxn = 120*2;
const int maxm = 5010;
struct node
{
    int to;
    int v;
    int flag;
    int next;
}edge[(maxn+maxm)*2];
struct ans_point
{
    int x;
    int flag;
}ans_p[maxn];
int index,pre[maxn],vis[maxn],S,T;
int in[maxn],out[maxn];
void add(int x,int y,int z)
{
    edge[index].to=y;
    edge[index].v=z;
    edge[index].flag=index+1;
    edge[index].next=pre[x];
    pre[x]=index++;
    edge[index].to=x;
    edge[index].v=0;
    edge[index].flag=index-1;
    edge[index].next=pre[y];
    pre[y]=index++;
}
int dfs(int u,int low)
{
    int i,used=0;
    if(u==T)
        return low;
    for(i=pre[u];i!=-1&&used<low;i=edge[i].next)
    {
        if(edge[i].v&&vis[edge[i].to]==vis[u]+1)
        {
            int a=dfs(edge[i].to,min(low-used,edge[i].v));
            edge[i].v-=a;
            edge[edge[i].flag].v+=a;
            used+=a;
        }
    }
    if(!used)
        vis[u]=-1;
    return used;
}
bool BFS()
{
    int i;
    queue<int>q;
    memset(vis,-1,sizeof(vis));
    vis[0]=1;
    q.push(0);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        for(i=pre[t];i!=-1;i=edge[i].next)
        {
            if(edge[i].v&&vis[edge[i].to]<0)
            {
                vis[edge[i].to]=vis[t]+1;
                q.push(edge[i].to);
            }
        }
    }
    if(vis[T]>0)
        return true;
    return false;
}
void cnt_dfs(int u)
{
    int i;
    vis[u]=1;
    for(i=pre[u];i!=-1;i=edge[i].next)
    {
        if(edge[i].v>0&&!vis[edge[i].to])
            cnt_dfs(edge[i].to);
    }
}
int main()
{
    int n,m,i,j;
    while(~scanf("%d%d",&n,&m))
    {
        index=1;
        memset(pre,-1,sizeof(pre));
        S=0,T=2*n+1;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&in[i]);
            add(i+n,T,in[i]);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&out[i]);
            add(S,i,out[i]);
        }
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y+n,INF);
        }
        int ans=0;
        while(BFS())
        {
            int a=dfs(0,INF);
            if(!a)break;
            ans+=a;
        }
        printf("%d\n",ans);
        memset(vis,0,sizeof(vis));
        cnt_dfs(0);
        int cnt=0;
        for(i=1;i<=n*2;i++)
        {
            if(i>n)
            {
                if(vis[i])
                {
                    ans_p[cnt].x=i;
                    ans_p[cnt++].flag=1;
                }
            }
            else
            {
                if(!vis[i])
                {
                    ans_p[cnt].x=i;
                    ans_p[cnt++].flag=0;
                }
            }
        }
        printf("%d\n",cnt);
        for(i=0;i<cnt;i++)
        {
            if(ans_p[i].x>n)
                    printf("%d ",ans_p[i].x-n);
            else printf("%d ",ans_p[i].x);
            if(ans_p[i].flag==0)
                printf("-\n");
            else printf("+\n");
        }
    }
}

 

posted @ 2015-10-30 21:01  sweat123  阅读(580)  评论(0编辑  收藏  举报