TOJ 3665 方格取数(2)(最大点权独立集)

描述

给你一个m*n的格子的棋盘,每个格子里面有一个非负数。

从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。

输入

包括多个测试实例,每个测试实例包括2整数m,n和m行n列的非负数(m<=50,n<=50)

输出

对于每个测试实例,输出可能取得的最大的和

样例输入

3 3
75 15 21
75 15 28
34 70 5

样例输出

188

题意

如上

题解

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

用最小割跑出来的是最小点权覆盖,再用sum-最小点权覆盖

把图黑白染色,黑色点连源点S流量a[i][j],白色点连汇点T流量a[i][j],然后每个相邻的黑白点连黑白边流量INF,跑最小割即可

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3
  4 const int maxn=1e5+5;
  5 const int maxm=2e5+5;
  6 int n,m,S,T;
  7 int deep[maxn],q[400000];
  8 int FIR[maxn],TO[maxm],CAP[maxm],COST[maxm],NEXT[maxm],tote;
  9
 10 void add(int u,int v,int cap)
 11 {
 12     TO[tote]=v;
 13     CAP[tote]=cap;
 14     NEXT[tote]=FIR[u];
 15     FIR[u]=tote++;
 16
 17     TO[tote]=u;
 18     CAP[tote]=0;
 19     NEXT[tote]=FIR[v];
 20     FIR[v]=tote++;
 21 }
 22 bool bfs()
 23 {
 24     memset(deep,0,sizeof deep);
 25     deep[S]=1;q[1]=S;
 26     int head=0,tail=1;
 27     while(head!=tail)
 28     {
 29         int u=q[++head];
 30         for(int v=FIR[u];v!=-1;v=NEXT[v])
 31         {
 32             if(CAP[v]&&!deep[TO[v]])
 33             {
 34                 deep[TO[v]]=deep[u]+1;
 35                 q[++tail]=TO[v];
 36             }
 37         }
 38     }
 39     return deep[T];
 40 }
 41 int dfs(int u,int fl)
 42 {
 43     if(u==T)return fl;
 44     int f=0;
 45     for(int v=FIR[u];v!=-1&&fl;v=NEXT[v])
 46     {
 47         if(CAP[v]&&deep[TO[v]]==deep[u]+1)
 48         {
 49             int Min=dfs(TO[v],min(fl,CAP[v]));
 50             CAP[v]-=Min;CAP[v^1]+=Min;
 51             fl-=Min;f+=Min;
 52         }
 53     }
 54     if(!f)deep[u]=-2;
 55     return f;
 56 }
 57 int maxflow()
 58 {
 59     int ans=0;
 60     while(bfs())
 61         ans+=dfs(S,1<<28);
 62     return ans;
 63 }
 64 void init()
 65 {
 66     tote=0;
 67     memset(FIR,-1,sizeof FIR);
 68 }
 69 int N,M,a[55][55],color[55][55],has[55][55],tot,sum,f;
 70 int main()
 71 {
 72     while(cin>>N>>M)
 73     {
 74         init();
 75         memset(color,0,sizeof color);
 76         tot=sum=0;
 77         for(int i=1;i<=N;i++)
 78         {
 79             if(i&1)f=1;
 80             else f=-1;
 81             for(int j=1;j<=M;f*=-1,j++)
 82             {
 83                 scanf("%d",&a[i][j]);
 84                 sum+=a[i][j];
 85                 has[i][j]=tot++;
 86                 color[i][j]=f;
 87             }
 88         }
 89         S=tot,T=S+1;
 90         for(int i=1;i<=N;i++)
 91             for(int j=1;j<=M;j++)
 92             {
 93                 if(color[i][j]==1)
 94                     add(S,has[i][j],a[i][j]);
 95                 else
 96                     add(has[i][j],T,a[i][j]);
 97                 if(color[i-1][j]==-1)add(has[i][j],has[i-1][j],1<<28);
 98                 if(color[i+1][j]==-1)add(has[i][j],has[i+1][j],1<<28);
 99                 if(color[i][j-1]==-1)add(has[i][j],has[i][j-1],1<<28);
100                 if(color[i][j+1]==-1)add(has[i][j],has[i][j+1],1<<28);
101             }
102         cout<<sum-maxflow()<<‘\n‘;
103     }
104     return 0;
105 }

原文地址:https://www.cnblogs.com/taozi1115402474/p/9535779.html

时间: 2024-10-12 16:30:07

TOJ 3665 方格取数(2)(最大点权独立集)的相关文章

HDU 1565 1569 方格取数(最大点权独立集)

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

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

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

hdoj 1569 方格取数 【最大点权独立集-&gt;最大流】

题目:hdoj 1569 方格取数 题意:中文题目,就不说题意了. 分类:最大流 |  dp 分析:dp的话应该是个数塔模型,不难做,这里讲转化为图的做法. 这个题目的关键在于转化为一个二分图,来求一个二分图的最大点权独立集,而最大点权独立集 = 点权和 - 最小点权覆盖 最小点权覆盖: 从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小. 最大点权独立集:找到二分图中权值和最大的点集,然后让任意点没有边. 而最小点权覆盖 = 最小割 = 最大流 = sum - 最大

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 1565 方格取数(2)(网络流之最大点权独立集)

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

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

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 预备知识: 对于一个无向