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 0x3fffffff
#define ii 50
#define N   3000
struct node {
 int u,v,w,next;
}bian[N*6];
int head[N],yong,s,t,dis[N];
void init(){
yong=0;
memset(head,-1,sizeof(head));
memset(dis,-1,sizeof(dis));
}
void addedge(int u,int v,int w) {
bian[yong].u=u;
bian[yong].v=v;
bian[yong].w=w;
bian[yong].next=head[u];
head[u]=yong++;
}
void add(int u,int v,int w) {
 addedge(u,v,w);
 addedge(v,u,0);
}
void bfs() {
int u,v,i;
queue<int>q;
q.push(t);
dis[t]=0;
while(!q.empty()) {
    u=q.front();
    q.pop();
    for(i=head[u];i!=-1;i=bian[i].next) {
        v=bian[i].v;
        if(dis[v]==-1) {
            dis[v]=dis[u]+1;
            q.push(v);
        }
    }
}
return ;
}
int ISAP() {
int sum=0;
bfs();
int  gap[N],cur[N],stac[N],top,i;
memset(gap,0,sizeof(gap));
for(i=s;i<=t;i++) {
    gap[dis[i]]++;
    cur[i]=head[i];
}
int k=s;
top=0;
while(dis[s]<t+1) {
     if(k==t) {
            int minn=inf,index;
        for(i=0;i<top;i++) {
            int e=stac[i];
            if(minn>bian[e].w) {
                minn=bian[e].w;
                index=i;
            }
        }
        for(i=0;i<top;i++) {
            int e=stac[i];
            bian[e].w-=minn;
            bian[e^1].w+=minn;
        }
        sum+=minn;
        top=index;
        k=bian[stac[top]].u;
     }
     for(i=cur[k];i!=-1;i=bian[i].next) {
       int  v=bian[i].v;
        if(bian[i].w&&dis[k]==dis[v]+1) {
            cur[k]=i;
            k=v;
            stac[top++]=i;
            break;
        }
     }
     if(i==-1) {
        int m=t+1;
        for(i=head[k];i!=-1;i=bian[i].next)
            if(m>dis[bian[i].v]&&bian[i].w) {
                m=dis[bian[i].v];
                cur[k]=i;
            }
            if(--gap[dis[k]]==0)break;
            gap[dis[k]=m+1]++;
            if(k!=s)
                k=bian[stac[--top]].u;
     }
}
return sum;
}
int main() {
    int n,m,i,j,T,id[ii][ii],cnt,sum,f=0;
    char ss[ii][ii];
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        cnt=1;sum=0;
        init();
        for(i=1;i<=n;i++) {
            scanf("%s",ss[i]+1);
            for(j=1;j<=m;j++) {
                if(ss[i][j]=='.'||ss[i][j]=='E')//记录总数
                    sum+=4;
                id[i][j]=cnt++;
            }
        }
        s=0;t=n*m+1;
        for(i=1;i<=n;i++)
        for(j=1;j<=m;j++) {
            if((i+j)&1) {//奇偶建图与源点相连
                if(ss[i][j]=='.')
                    add(s,id[i][j],inf);//必然不割
                if(ss[i][j]=='D')//必割
                    add(s,id[i][j],0);
                if(ss[i][j]=='E')//任意选择
                    add(s,id[i][j],4);
                if(i>=2) {
                    if(ss[i][j]=='.'||ss[i][j]=='E') {
                        if(ss[i-1][j]=='.'||ss[i-1][j]=='E')add(id[i][j],id[i-1][j],2);//
                        if(ss[i-1][j]=='D')add(id[i][j],id[i-1][j],0);//
                    }
                    else
                        add(id[i][j],id[i-1][j],0);
                }
                if(j>=2) {
                   if(ss[i][j]=='.'||ss[i][j]=='E') {
                        if(ss[i][j-1]=='.'||ss[i][j-1]=='E')add(id[i][j],id[i][j-1],2);
                        if(ss[i][j-1]=='D')add(id[i][j],id[i][j-1],0);
                    }
                    else
                        add(id[i][j],id[i][j-1],0);
                }
                if(i<=n-1){
                     if(ss[i][j]=='.'||ss[i][j]=='E') {
                        if(ss[i+1][j]=='.'||ss[i+1][j]=='E')add(id[i][j],id[i+1][j],2);
                        if(ss[i+1][j]=='D')add(id[i][j],id[i+1][j],0);
                    }
                    else
                        add(id[i][j],id[i+1][j],0);
                }
                if(j<=m-1) {
                      if(ss[i][j]=='.'||ss[i][j]=='E') {
                        if(ss[i][j+1]=='.'||ss[i][j+1]=='E')add(id[i][j],id[i][j+1],2);
                        if(ss[i][j+1]=='D')add(id[i][j],id[i][j+1],0);
                        }
                    else
                        add(id[i][j],id[i][j+1],0);
                }
            }
            else {//与汇点相连
                if(ss[i][j]=='.')
                    add(id[i][j],t,inf);
                if(ss[i][j]=='E')
                    add(id[i][j],t,4);
                if(ss[i][j]=='D')
                    add(id[i][j],t,0);
            }
        }
        printf("Case %d: ",++f);
        printf("%d\n",sum-ISAP());
    }
return 0;
}

hdu 4859 最大点权独立集的变形(方格取数的变形),布布扣,bubuko.com

时间: 2024-12-13 10:25:01

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

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

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

hdu 1565 最大点权独立集

题意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. 链接:点我 分析转自:点我    二分图最小点覆盖和最大独立集都可以转化为最大匹配求解.在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集. 二分图最小点权覆盖 从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小. 建模: 原二分图中的边(u,

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

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

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 1565 1569 方格取数(最大点权独立集)

HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点连向黑点.白点连向汇点,容量都为点容量.然后黑白之间相邻的就连一条容量无限大的边 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using names

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

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

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:方格取数(1)(最大点权独立集)***

http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意:中文. 思路:一个棋盘,要使得相邻的点不能同时选,问最大和是多少,这个问题就是最大点权独立集. 可以转化为所有的点权 - 最小点权覆盖集(最小割) = 最大点权独立集. 转载两个的定义:这里. 覆盖集(vertex covering set,VCS)是无向图的一个点集,使得该图中所有边都至少有一个端点在该集合内.形式化的定义是点覆盖集为G'VV∈(,)uvE∀∈,满足对于,都有 或成立,即,'uV

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个格子不能相邻,并且取出的