题目链接:https://cn.vjudge.net/problem/HDU-1565

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

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

看了一下题目,立刻就想起来曾经好像在网络流专题里做过类似题目,

一翻博客,果然找到了这题的brother:http://www.cnblogs.com/dilthey/p/7401563.html

题解:

解法①:

既然,连这题的加强版 HDU 1569 - 方格取数 都可以用网络流做,这题当然也可以,代码几乎就是一点点修改:

 #include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAX 405
#define INF 0x3f3f3f3f
#define id(i,j) (i-1)*n+j
using namespace std;
struct Edge{
int u,v,c,f;
};
struct Dinic
{
int s,t;
vector<Edge> E;
vector<int> G[MAX];
bool vis[MAX];
int lev[MAX];
int cur[MAX];
void init(int l,int r)
{
E.clear();
for(int i=l;i<=r;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
int m=E.size();
G[from].push_back(m-);
G[to].push_back(m-);
}
bool bfs()
{
memset(vis,,sizeof(vis));
queue<int> q;
q.push(s);
lev[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=,_size=G[now].size();i<_size;i++)
{
Edge edge=E[G[now][i]];
int nex=edge.v;
if(!vis[nex] && edge.c>edge.f)
{
lev[nex]=lev[now]+;
q.push(nex);
vis[nex]=;
}
}
}
return vis[t];
}
int dfs(int now,int aug)
{
if(now==t || aug==) return aug;
int flow=,f;
for(int& i=cur[now],_size=G[now].size();i<_size;i++)
{
Edge& edge=E[G[now][i]];
int nex=edge.v;
if(lev[now]+ == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>)
{
edge.f+=f;
E[G[now][i]^].f-=f;
flow+=f;
aug-=f;
if(!aug) break;
}
}
return flow;
}
int maxflow()
{
int flow=;
while(bfs())
{
memset(cur,,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
}dinic;
int n,grid[][],sum;
int d[][]={{,+},{+,},{,-},{-,}};
bool inmap(int i,int j){return( <=i && i<=n && <=j && j<=n );}
int main()
{
while(scanf("%d",&n)!=EOF)
{
dinic.init(,n*n+);
dinic.s=, dinic.t=n*n+;
sum=;
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
scanf("%d",&grid[i][j]);
sum+=grid[i][j];
if((i+j)%)
{
for(int k=;k<;k++) if(inmap(i+d[k][],j+d[k][])) dinic.addedge(id(i,j), id(i+d[k][],j+d[k][]), INF);
dinic.addedge(dinic.s, id(i,j), grid[i][j]);
}
else dinic.addedge(id(i,j), dinic.t, grid[i][j]);
}
}
printf("%d\n",sum-dinic.maxflow());
}
}

解法②:

当然,既然放在状压DP专题,当然也说明了这种题目,在列数在比较小的情况下,可以用状压DP做(HDU1569因为列数达到50,所以不行);

首先,由于1<<20的状态数,还是偏大了点,依然选择类似于http://www.cnblogs.com/dilthey/p/7604432.html中筛选状态的操作,得到最多的状态数为17711;

然后,设dp[r][i]:表示第r行为状态i时(显然这个i在二进制表示下,每一位上,0表示不取对应位置的数,1表示取),从第一行到第r行能取到的最大的和;

而要得到dp[r][i],只需要把dp[r-1][j]枚举一遍,做相应的一定的计算,再保证维护dp[r][i]始终为最大即可,这就是状态转移;

其中所谓“做相应的一定的计算”,需要一个calc(r, state)函数:

  calc(r, state)返回值为:第r行当状态为state时,取到的数之和;

AC代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,grid[][],ans;
int dp[][];
int state[],state_cnt;
int calc(int r,int state)
{
int ans=;
int cnt=n;
while(state)
{
if(state&) ans+=grid[r][cnt];
state=state>>;
cnt--;
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(dp,,sizeof(dp));
for(int i=;i<=n;i++) for(int j=;j<=n;j++) scanf("%d",&grid[i][j]);
state_cnt=;
for(int i=;i<(<<n);i++)
{
if(i&(i<<)) continue;
dp[][state_cnt]=calc(,i);
state[state_cnt++]=i;
}
for(int r=;r<=n;r++)
{
for(int i=;i<state_cnt;i++)//枚举第r行状态
{
for(int j=;j<state_cnt;j++)//枚举第r-1行状态
{
if(state[i]&state[j]) continue;
dp[r][i]=max(dp[r][i],dp[r-][j]+calc(r,state[i]));
}
}
} ans=;
for(int i=;i<state_cnt;i++) ans=max(ans,dp[n][i]);
printf("%d\n",ans);
}
}

PS.本题其实和POJ 1185:http://www.cnblogs.com/dilthey/p/7604432.html比较像,做法思路一脉相承,会做POJ1185的话,做这题应该不难。

HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]的更多相关文章

  1. hdu 2167 方格取数 【状压dp】(经典)

    <题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...

  2. hdu 1565 方格取数(1) 状态压缩dp

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

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

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

  4. 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

      HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...

  5. HDU 1565 方格取数(1) 轮廓线dp

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

  6. HDU 1565 方格取数 状压dp

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

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

    方格取数(1)                                                                 Time Limit: 10000/5000 MS (J ...

  8. HDU 1565 方格取数(1)(最大点权独立集)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格 ...

  9. HDU 1565 方格取数(1) ——插头DP

    [题目分析] 其实直接状压就可以了. 但是有点闲,又写了一个可读性极差,智商低下,很(gou)好(pi)的代码 [代码] #include <cstdio> #include <cs ...

随机推荐

  1. SpringBoot------Eclipce配置Spring Boot

    步骤一: 步骤二: 点击左下角Eclipse图标下的“Popular”菜单,选择Spring安装(已安装的插件在Installed中显示),一直按步骤确定就好了,如果中途下载超时什么的,就看看自己的网 ...

  2. express不是内部或外部命令,也不是可运行的程序或批处理文件

    如上安装了express以后,仍然报如下错误:express不是内部或外部命令,也不是可运行的程序或批处理文件 原因是版本问题:当前版本是4.0.0,改成3.5.0即可运行. npm install ...

  3. python关键字与标识符

    编程语言众多,但每种语言都有相应的关键字,Python 也不例外,它自带了一个 keyword 模块,用于检测关键字. 关键字列表 进入 Python 交互模式,获取关键字列表: >>&g ...

  4. 【遥感影像】Python GDAL 像素与坐标对应

    转:https://blog.csdn.net/theonegis/article/details/50805520 https://blog.csdn.net/wsp_1138886114/arti ...

  5. Kafka(一)-- 初体验

    一.概念 Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据. 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素. 这些 ...

  6. 使用 TXT 文本存储

    将爬取的数据以 TXT 文本形式存储: import requests data = requests.get('http://www.baidu.com/').text with open('/tm ...

  7. Unity透明Shader

    Shader "Custom/Blocks" { Properties { _Color (,,,) _MainTex ("Albedo (RGB)", 2D) ...

  8. [Shell] Backtick vs $() 两种方式内嵌值

    使用反撇号(重音符)`command` 和 $(command) 都表示内嵌shell命令. for file in $(ls); do echo $file done for file in `ls ...

  9. error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

    更新的软件可以解决 TortoiseGit-preview-2.5.7.0-20180127-b2d00f8-64bit.msi和Git-2.16.2-64-bit.exe. 链接地址为: https ...

  10. PHP 中文字符串截取

    $str = "abcdef啊啊吧啊"; function my_sub($str, $st ,$len){ $ret = ""; for( $st; $len ...