最小点权覆盖 && 最大点权独立集 zoj 3165 hdu 1565 poj 2125

最小点权覆盖集的总权值 + 最大点权独立集的总权值 = 图的总权值

所以最大点权独立集的题目都可以转换成最小点权覆盖集的题目

注意:图必须是二分图 否则是NP问题

两道典型的题目

最大点权独立集

hdu 1565 http://acm.hdu.edu.cn/showproblem.php?pid=1565

将方格黑白染色(类似于国际象棋的棋盘),然后出现二分图了,怎么建边?代码已经很详细了

View Code
#include<stdio.h>
#include<string.h>
const int MAX=1010;
const int INF=1000000000;
struct{
    int v,c,next;
}edge[100000];
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;}
int 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,maxflow=0,aug=-1,v;
    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;
}
int n;
int ID(int x,int y){
    return (x-1)*n+y;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int w;
        memset(head,-1,sizeof(head));
        E=0;
        int S=0,T=n*n+1;
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&w);
                sum+=w;
                if((i+j)%2==0){
                    add_edge(S,ID(i,j),w,0);
                    if(i<n) 
                    {
                        add_edge(ID(i,j),ID(i+1,j),INF,0);
                    
                    }
                    if(j<n)
                    {
                        add_edge(ID(i,j),ID(i,j+1),INF,0);
                    }
                    if(i>1)
                    {
                        add_edge(ID(i,j),ID(i-1,j),INF,0);
                    }
                    if(j>1)
                    {
                        add_edge(ID(i,j),ID(i,j-1),INF,0);
                    }
                }
                else 
                {
                    add_edge(ID(i,j),T,w,0);
                }
            }
        }
        int tmp=SAP(S,T,T+1);
        printf("%d\n",sum-tmp);
    }
    return 0;
}

 

最小点权覆盖集

http://www.cnblogs.com/wuyiqi/archive/2012/03/13/2393481.html

 

最大点权独立集 zoj 3165  (输出解,基本和上题一样,最小点覆盖的补图就是最大点独立集)

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=250;
const int INF=1000000000;
struct{
    int v,c,next;
}edge[20000];
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;}
int 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,maxflow=0,aug=-1,v;
    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;
}
int n,m;
int A,B;
bool flag[MAX];
void dfs(int s){
    flag[s]=true;//printf("s=%d\n",s);
    for(int i=head[s];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(!flag[v] && edge[i].c){
            dfs(v);
        }
    }
}
int main()
{
    
    int s;
    while(scanf("%d%d%d",&m,&n,&s)!=EOF)
    {
        int w;
        memset(head,-1,sizeof(head));
        E=0;A=0;B=0;
        int S=0,T=m+n+1;
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&w);
            sum+=w;
            add_edge(S,i,w,0);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w);
            sum+=w;
            add_edge(m+i,T,w,0);
        }
        int a,b;
        for(int i=0;i<s;i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,m+b,INF,0);
        }
        int max_flow=SAP(S,T,T+1);
        int ans=sum-max_flow;
        memset(flag,false,sizeof(flag));
        dfs(S);
        for(int i=1;i<=m;i++)
        {
            if(flag[i]) A++;
        }
        for(int i=1;i<=n;i++)
        {
            if(!flag[i+m]) B++;
        }
        int f=0;
        printf("%d %d %d\n",ans,A,B);
        for(int i=1;i<=m;i++)
        {
            if(flag[i])
            {
                if(!f)
                {
                    f=1;
                    printf("%d",i);
                }
                else
                {
                    printf(" %d",i);
                }
            }
        }
        puts("");
        f=0;
        for(int i=1;i<=n;i++)
        {
            if(!flag[i+m])
            {
                if(!f)
                {
                    f=1;
                    printf("%d",i);
                }
                else
                {
                    printf(" %d",i);
                }
            }
        }
        puts("");
    }
    return 0;
}

 

 

posted @ 2012-07-16 19:46  Because Of You  Views(1034)  Comments(0Edit  收藏  举报