hdu1565+hdu1569(最大点权独立集)

传送门:hdu1565 方格取数(1)

传送门:hdu1569 方格取数(2)

定理:
1. 最小点权覆盖集=最小割=最大流
2. 最大点权独立集=总权-最小点权覆盖集

步骤:

1. 先染色,取一个点染白色,和它相邻的点染黑色
2. 每个白点向它相邻的黑点连一条边,容量为 inf (无穷大)
3. 增加源点S,向每一个白色点连一条边,容量为白点的权
4. 增加汇点T,每个黑点向T连一条边,容量为黑点的权

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <limits.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-6
#define N 2510
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PII pair<int,int>
using namespace std;
inline int read()
{
    char ch=getchar();
    int x=0,f=1;
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch<=‘9‘&&ch>=‘0‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m,vs,vt,tot,NV;
int head[N],gap[N],level[N],q[N];
struct edge
{
    int v,w,next;
    edge(){}
    edge(int v,int w,int next):v(v),w(w),next(next){}
}e[N*N];
void addedge(int u,int v,int w)
{
    e[tot]=edge(v,w,head[u]);
    head[u]=tot++;
    e[tot]=edge(u,0,head[v]);
    head[v]=tot++;
}
void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}
/***************************SAP***********************/
void bfs(int vt)
{
    memset(level,-1,sizeof(level));
    memset(gap,0,sizeof(gap));
    level[vt]=0;
    gap[level[vt]]++;
    queue<int>que;
    que.push(vt);
    while(!que.empty()) {
        int u=que.front();
        que.pop();
        for(int i=head[u]; i!=-1; i=e[i].next) {
            int v=e[i].v;
            if(level[v]!=-1)continue;
            level[v]=level[u]+1;
            gap[level[v]]++;
            que.push(v);

        }
    }
}
int pre[N];
int cur[N];
int SAP()
{
    bfs(vt);
    memset(pre,-1,sizeof(pre));
    memcpy(cur,head,sizeof(head));
    int u=pre[vs]=vs,flow=0,aug=inf;
    gap[0]=NV;
    while(level[vs]<NV) {
        bool flag=false;
        for(int &i=cur[u]; i!=-1; i=e[i].next) {
            int v=e[i].v;
            if(e[i].w&&level[u]==level[v]+1) {
                flag=true;
                pre[v]=u;
                u=v;
                aug=min(aug,e[i].w);
                if(v==vt) {
                    flow+=aug;
                    for(u=pre[v]; v!=vs; v=u,u=pre[u]) {
                        e[cur[u]].w-=aug;
                        e[cur[u]^1].w+=aug;
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag)continue;
        int minlevel=NV;
        for(int i=head[u]; i!=-1; i=e[i].next) {
            int v=e[i].v;
            if(e[i].w&&level[v]<minlevel) {
                minlevel=level[v];
                cur[u]=i;
            }
        }
        if(--gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return flow;
}
/**************************SAP**********************/
int sum,x,num[55][55],id[55][55];
bool judge(int i,int j)
{
    return i>=1&&i<=n&&j>=1&&j<=m;
}
void build()
{
    sum=x=0;NV=n*m+2;
    vs=0;vt=n*m+1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            x++;
            num[i][j]=read();
            sum+=num[i][j];
            id[i][j]=x;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if((i+j)&1)
            {
                addedge(id[i][j],vt,num[i][j]);
            }
            else
            {
                addedge(vs,id[i][j],num[i][j]);
                for(int x=-1;x<=1;x++)
                for(int y=-1;y<=1;y++)
                {
                    if(x+y==0||x==y||!judge(x+i,y+j))continue;
                    addedge(id[i][j],id[i+x][j+y],inf);
                }
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)>0)
    {
        init();
        build();
        printf("%d\n",sum-SAP());
    }
}

时间: 2024-08-11 16:27:08

hdu1565+hdu1569(最大点权独立集)的相关文章

hdu1565方格取数(1)【最大流||最大点权独立集】

Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188 预备知识: 对于一个无向

HDU1569 最大流(最大点权独立集)

方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 68 Accepted Submission(s): 33   Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. In

hdu1565方格取数(1) 最大流之 最大点权独立集

//给一个n*n的矩阵,问从这个矩阵中若干数,这些数不相邻 //问这些数的最大值为多少 //1. 最小点权覆盖集=最小割=最大流 //2. 最大点权独立集=总权-最小点权覆盖集 //将(i+j)%2 == 1分为x集,将(i+j)%2==0分为y集 //对x集向y集相邻的边引入权值为inf的边 //源点向x集引入权值为该点权值的边 , 从y集向汇点引入权值为该点权值的边 //那么答案是其最大点权独立集 #include<cstdio> #include<cstring> #incl

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

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

题目要求我们选尽量多的点,同时两两不相邻 可以想到把棋盘按照国际象棋的棋盘样式染色,那同一种颜色的点之间肯定是不相邻的,同时我们也就把图转化为了一个二分图 题目要求也就变成了求这个二分图里的最大点权独立集 最大独立集:包含尽量多顶点的集合,其中任意两点不相邻,所谓的不相邻也就是两点没有连边 最小点覆盖:选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖) 最大点权独立集=总权值-最小点权覆盖集 其实不难理解,看看定义就知道了 假设现在已经求出了最小点覆盖,那把这些点去掉,剩下的点肯定是

hdoj 1569 方格取数(2) 【最小割】 【最大点权独立集】

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5589    Accepted Submission(s): 1741 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff