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
Author
ailyanlu
Source
 
 
正解:网络流
解题报告:
  网络流24题第9题。同样是可以转换为最大点权和独立集,求最小割跑最大流。自己的题解:

  模型:建图+最小割

  总结:

  和前面做的几道题很类似,都是求最大独立集。事实上都可以转换成二分图,然后按照最小割模型来做。

  考虑这道题说不能选取有相邻边的格子中的数,相当于是如果选取了当前格子,那么周围相邻的四个格子都不能再选。这个模型显然就是一个二分图,所以首先我们可以先把全图进行二分图染色,对于一个点坐标为(i,j),如果(i+j)%2==0,那么染成白色;否则,染成黑色。然后新建源点S,向所有白色点连一条容量为该点点权的有向边;新建汇点T,所有黑色点连一条容量为该点点权的有向边。对于所有白色点,向四周的所有黑色点都连一条容量为无穷的有向边。如此以来我们构出了一张图(跟前几道题一样的说)。

  显然我们希望得到选取的尽可能多的格子,由于都是正数所以肯定能选尽量选。但是如果选了一个格子,就意味着四周的全都不能再选了,也就是说如果我们把ans初值记为所有格子权值之和,那么我们每次因为选择了一个格子就会失去周围四个的权值,需要从ans中减掉。这跟什么很像呢?最大半连通子图!是的,一样的做法,用总的和减去最小割就可以得到我们期望的最大值。

  
 
 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = ;
const int MAXM = ;
const int inf = (<<);
int n,sum,S,T,ecnt,ans;
int a[MAXN][MAXN],deep[MAXN*MAXN];
int first[MAXN*MAXN];
queue<int>Q;
struct edge{
int next,to,f;
}e[MAXM]; inline int getint()
{
int w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} inline void link(int x,int y,int z){
e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].to=y; e[ecnt].f=z;
e[++ecnt].next=first[y]; first[y]=ecnt; e[ecnt].to=x; e[ecnt].f=;
} inline bool bfs(){
while(!Q.empty()) Q.pop();
for(int i=;i<=T;i++) deep[i]=;
Q.push(S); deep[S]=;
while(!Q.empty()) {
int u=Q.front(); Q.pop();
for(int i=first[u];i;i=e[i].next) {
int v=e[i].to;
if(e[i].f && !deep[v]) deep[v]=deep[u]+,Q.push(v);
}
}
if(deep[T]!=) return true;
return false;
} inline int Dinic(int x,int remain){
if(remain== || x==T) return remain;
int f,flow=;
for(int i=first[x];i;i=e[i].next) {
int v=e[i].to;
if(e[i].f && deep[v]==deep[x]+){
f=Dinic(v,min(remain,e[i].f));
if(f){
flow+=f; e[i].f-=f; e[i^].f+=f;
remain-=f; if(remain==) return flow;
} else deep[v]=-;
}
}
return flow;
} inline void work(){
while(scanf("%d",&n)!=EOF) {
sum=;
for(int i=;i<=n;i++) for(int j=;j<=n;j++) a[i][j]=getint(),sum+=a[i][j];
S=n*n+;T=S+; ecnt=; memset(first,,sizeof(first));
for(int i=;i<=n;i++) for(int j=;j<=n;j++) if((i+j)%==) link(S,(i-)*n+j,a[i][j]); else link((i-)*n+j,T,a[i][j]);//黑白染色
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
if((i+j)%) continue;
if(i!=) link((i-)*n+j,(i-)*n+j,inf);
if(j!=) link((i-)*n+j,(i-)*n+j-,inf);
if(j!=n) link((i-)*n+j,(i-)*n+j+,inf);
if(i!=n) link((i-)*n+j,i*n+j,inf);
}
ans=;
while(bfs()) ans+=Dinic(S,inf);
printf("%d\n",sum-ans);
}
} int main()
{
work();
return ;
}

HDU1565 方格取数(1)的更多相关文章

  1. HDU1565 方格取数(1) —— 状压DP or 插头DP(轮廓线更新) or 二分图点带权最大独立集(最小割最大流)

    题目链接:https://vjudge.net/problem/HDU-1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory L ...

  2. HDU-1565 方格取数(1)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Me ...

  3. HDU1565 方格取数 &&uva 11270 轮廓线DP

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  4. Hdu-1565 方格取数(1) (状态压缩dp入门题

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  5. HDU1565 方格取数1(构图+网络流最大独立集合)

    题目大意:给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. 解题思路:最大点 ...

  6. HDU1565方格取数

    典型的状态压缩DP问题.第i行的取法只受到第i-1行的影响.首先每一行的取法要相容(不能有两个相邻),然后相邻行之间也要相容.将每一个格子看做两种状态,1表示取,0表示不取.这样每一行就是一个01串, ...

  7. HDU1565 方格取数(1)(状态压缩dp)

    题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...

  8. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  9. HDU 1565&1569 方格取数系列(状压DP或者最大流)

    方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

随机推荐

  1. 【BZOJ1923】[Sdoi2010]外星千足虫 高斯消元

    [BZOJ1923][Sdoi2010]外星千足虫 Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用“点足机”的统计结果.每行 ...

  2. 《从零开始学Swift》学习笔记(Day 42)——构造函数调用规则

    原创文章,欢迎转载.转载请注明:关东升的博客 在构造函数中可以使用构造函数代理帮助完成部分构造工作.类构造函数代理分为横向代理和向上代理,横向代理只能在发生在同一类内部,这种构造函数称为便利构造函数. ...

  3. 关于angularjs中的ng-class的使用

    在angularjs中,包子认为ng-class的用法是相当的大,这个相当于jquery的addClass和removeClass.在这个地方,废话不多说,直接上一小段代码 当kefu这个变量为真的时 ...

  4. IOS开发复习笔记(4)-TableView

    总结几个TableView常用的代码 1.初始化方面 static string CellIndetifier=@"cellIndetifier"; -(NSInteger)num ...

  5. 浅析 Pycharm 内存、cpu 占用率

    浅析 Pycharm  内存.cpu 占用率 本机配置参数: ------------------------------------------ Windows 10 专业版   X64 ----- ...

  6. 关于handler内存泄露的问题

    在使用Handler更新UI的时候.我是这样写的: public class SampleActivity extends Activity { private final Handler mLeak ...

  7. 004-ibus输入法,快捷键,浏览器

    一.输入法 用 root 身份在终端下,运行下面命令: yum install ibus-pinyin ibus ibus-gtk ibus-qt 使用im-chooser命令,选择ibus为默认输入 ...

  8. Linux基础系列:常用命令(4)_系统监控

    1. 系统监视和进程控制工具—top和free 1) top命令的功能:top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. 2) ...

  9. 去重除了indexOf的其他方法(使用对象Key的方法)及统计重复次数

    1.去重: 法1:使用数组IndexOf去重 法2:使用对象Key: <script> var arr1 = [1,13,24,11,11,14,1,2]; let unique = fu ...

  10. java中类名.class, class.forName(), getClass()区别

    Class对象的生成方式如下: 1.类名.class           说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象 2.Cla ...