码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1565:最大点权独立集(网络流)

时间:2016-01-20 22:33:52      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

题目要求我们选尽量多的点,同时两两不相邻

可以想到把棋盘按照国际象棋的棋盘样式染色,那同一种颜色的点之间肯定是不相邻的,同时我们也就把图转化为了一个二分图

题目要求也就变成了求这个二分图里的最大点权独立集

 

最大独立集:包含尽量多顶点的集合,其中任意两点不相邻,所谓的不相邻也就是两点没有连边

最小点覆盖:选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖)

 

最大点权独立集=总权值-最小点权覆盖集

 

 

其实不难理解,看看定义就知道了

假设现在已经求出了最小点覆盖,那把这些点去掉,剩下的点肯定是不相邻的,也就是说剩下的点可以构成一个独立集

而我们现在求出的覆盖是最小的,所以自然得到的独立集也就是最大的了

那问题就转化为了求最小点权覆盖集

 

而二分图的最小点覆盖、最小点权覆盖集都可用网络流求解

构图:

超级源点与左边集合的每一点相连,若是求最小点覆盖,权值为1,若是求最小点权覆盖集,权值为该点的点权

超级汇点与右边集合的每一点相连,权值同上

然后将二分图原有的边加进图中,权值为无穷大

 

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#define ll long long
#define mems(a,b) memset(a,b,sizeof(a))
#define ls pos<<1
#define rs pos<<1|1

using namespace std;
const int MAXN = 500;
const int MAXE = 40500;
const int INF = 99999999;

struct node{
    int s,e,next,cost,val;
    node(){}
    node(int a,int b,int c,int d):s(a),e(b),next(c),val(d){}
}edge[MAXE];
int tot,ans,n;
int first[MAXN],dep[MAXN],gap[MAXN];
int mat[50][50];
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};

void init(){
    tot=0;
    mems(first,-1);
}

void addedge(int u,int v,int w){
    //cout<<u<<‘\t‘<<v<<‘\t‘<<w<<endl;
    edge[tot]=node(u,v,first[u],w);
    first[u]=tot++;
    edge[tot]=node(v,u,first[v],0);
    first[v]=tot++;
}

int sap(int src,int des){
    memset(dep,0,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0]=des+1;
    int top=0,ans=0,u=src,i;
    int cur[MAXN],s[MAXE];
    //s[top++]=src;
    for(i=0;i<=des;i++)
        cur[i]=first[i];
    while(1){
        if(u==des){
            int minv=INF,pos;
            for(i=0;i<top;i++){
                if(minv>edge[s[i]].val){
                    minv=edge[s[i]].val;
                    pos=i;
                }
            }
            for(i=0;i<top;i++){
                edge[s[i]].val-=minv;
                edge[s[i]^1].val+=minv;
            }
            ans+=minv;
            top=pos;
            u=edge[s[pos]].s;
        }
        for(i=cur[u];i!=-1;i=edge[i].next)
            if(edge[i].val&&dep[u]==dep[edge[i].e]+1)
                break;
        if(i!=-1){
            cur[u]=i;
            s[top++]=i;
            u=edge[i].e;
        }
        else{
            if(--gap[dep[u]]==0) break;
            int mindep=des+1;
            for(i=first[u];i!=-1;i=edge[i].next){
                if(!edge[i].val) continue;
                if(mindep>dep[edge[i].e]){
                    mindep=dep[edge[i].e];
                    cur[u]=i;
                }
            }
            dep[u]=mindep+1;
            gap[dep[u]]++;
            if(u!=src) u=edge[s[--top]].s;
        }
    }
    return ans;
}

bool ing(int x,int y){
    if(x>=0&&x<n&&y>=0&&y<n) return true;
    return false;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        init();
        int tot=0;
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++){
            scanf("%d",&mat[i][j]);
            tot+=mat[i][j];
        }
        int src=0;
        int des=n*n+1;
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++){
            if((i+j)%2==0) addedge(src,i*n+j+1,mat[i][j]);
            else addedge(i*n+j+1,des,mat[i][j]);
        }
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        if((i+j)%2==0)
        for(int k=0;k<4;k++){
            int x=i+dx[k];
            int y=j+dy[k];
            if(!ing(x,y)) continue;
            addedge(i*n+j+1,x*n+y+1,INF);
        }
        printf("%d\n",tot-sap(src,des));
    }
    return 0;
}
View Code

 

HDU 1565:最大点权独立集(网络流)

标签:

原文地址:http://www.cnblogs.com/luxiaoming/p/5146566.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!