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


题目清晰明了,这道题应该用dp。

自然地想到$dp[i][j]$表示位置$(i, j)$的最大值,但是在状态转移的时候推不出来。

这是因为子状态缺少表示选择情况的维度,即:你不知道某一个特定的点有没有被取。

因此自然地想到$dp[i][j][s]$其中$s$储存着一个状态。

但是经过简单的计算就可以发现,时间复杂度过高,即便这道题有5000ms的时限都妥妥的TLE。

因此我们需要状态压缩。

所以想到了$dp[i][s]$其中$i$表示第$i$行,而$s$表示这一行的选择状态,用一个二进制数储存。(0为留下1为取走)

思考一下不难得出状态转移方程:

dp[i][s1] = max(dp[i][s1], dp[i - ][s2] + tmp);

其中$tmp$为第$i$行在$s1$状态下的值,$dp$数组初始化也是一样的。

要注意,题目中说明了格子不能相邻,所以在预处理的时候可以凭此缩小枚举范围。(不缩小会炸)

大致思路就是这样了,具体的一下优化因人而异。有一个要注意的点就是杭电最近会出玄学结果,刚开始本蒟蒻开小了数组导致越界,结果结果是WA,害得调了很久才发现。

完整AC代码如下:(好像是495ms吧)

 #include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std; inline int read() { } const int maxn = ; int n;
int sq[maxn][maxn];
int top[maxn], ok[]; void init() {
int tp = , co = ;
for(int i = ; i < ( << (maxn - )); i++) {
if(!(i&(i<<))) {
ok[tp++] = i;
// cout << i << endl;
}
if(i == ( << co) - ) top[co++] = tp;
}
// cout << top << endl;
return ;
} int dp[maxn][]; int value(int line, int state) {
int ans = , pos, t = ;
while(state) {
pos = state % ;
if(pos == ) ans += sq[line][t];
t++;
state /= ;
}
return ans;
} void dp_init() {
// cout << top << endl;
for(int i = ; i < n; i++) {
for(int s = ; s < top[n]; s++) {
dp[i][s] = value(i, ok[s]);
// cout << dp[i][s] << ' ';
}
// cout << endl;
}
return ;
} void solve() {
for(int i = ; i < n; i++) {
for(int s1 = ; s1 < top[n]; s1++) {
int tmp = dp[i][s1];
for(int s2 = ; s2 < top[n]; s2++) {
if(!((ok[s1] | ok[s1] << | ok[s1] >> ) & ok[s2])) {
dp[i][s1] = max(dp[i][s1], dp[i - ][s2] + tmp);
}
}
}
}
return ;
} int main() {
init();
// for(int i = 1; i <= 20; i++) cout << top[i] << ' ';
// cout << endl;
while(scanf("%d", &n) != EOF) {
for(int i = ; i < n; i++) {
for(int j = ; j < n; j++) {
scanf("%d", &sq[i][j]);
}
}
dp_init();
solve();
int ans = ;
for(int i = ; i < top[n]; i++) {
ans = max(ans, dp[n - ][i]);
}
printf("%d\n", ans);
}
return ;
}

题外话:洛谷上好像有一道类似的紫题(网络流24题的),只不过不是正方形是长方形,而且实现也只有1000ms。

题解 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)

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

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

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

  7. HDU1565方格取数

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

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

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

  9. 题解 P1004 方格取数

    传送门 动态规划Yes? 设i为路径长度,(为什么i这一维可以省掉见下)f[j][k]表示第一个点到了(j,i-j),第二个点到了(k,j-k) 则 int ji=i-j,ki=i-k; f[j][k ...

  10. 洛谷 P1004 方格取数 题解

    P1004 方格取数 题目描述 设有 \(N \times N\) 的方格图 \((N \le 9)\),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字\(0\).如下图所示(见样例): ...

随机推荐

  1. label标签的可访问性问题

    label标签可以优雅地扩大表单控件元素的点击区域.例如,单纯的单选框点击区域就鼻屎那么大的地方,经常会点不到位置.因此,label标签的使用对于提高页面的可用性可访问性是很有帮助的. 其实,它的样子 ...

  2. 3ds Max脚本的使用实例教程

    本教程主要讲解了一个关于草地脚本的使用,应用到max与photoshop的一些命令及参数设置. 这个场景使用了3DSMAX5.1进行建模,使用VRAY渲染器进行的渲染,并且在最后使用PHOTOSHOP ...

  3. 支持JSONP跨域的对象

    支持JSONP跨域的对象 1:img 2:iframe 3:link 4:script 为什么,JSONP 最终选择是 script 实现呢?度娘来也! 平常我们进行JSONP请求数据,因为 json ...

  4. Ajax通过script src特性加载跨域文件 jsonp

    <!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>Do ...

  5. c traps and pitfalls reading notes(2)

    1.运算符优先级,这个我是肯定记不住,每次遇到的时候都纠结下,然后去查下,或者直接括号,但是括号太多,你懂得,要用notepad才能理清各种层次.这里啦个下来,留着参考.

  6. python基础4(小数据池,编码,深浅拷贝)

    1.==与is == 比较值是否相等 is比较内存地址是否相同 2.小数据池 为了节省内存,当数据在一个范围里的时候,两个值相同的变量指向的是小数据池里的同一个地址 数字范围:-5 ~ 256 num ...

  7. dll签名两种方法

    以下两种签名方法,都是对csp.dll签名,都不是CA颁发的,且效果不同, 一:通过自建证书签名 下载windows sdk,成功安装后,包括makecert.exe, cert2spc.exe, p ...

  8. mysql-基础和基本指令

    基础: 1.数据库模式:简单的说:就是一个数据库用户所拥有的数据库的对象.   比如scott用户建立了表,索引,视图,存储过程等对象,那么这些对象就构成了schema   scott .有时用作数据 ...

  9. ftoa浮点型转换成字符串

    #include <stdio.h> bool ftos(float num,char *s,int n) {     int temp; float t=num; int pn=0; b ...

  10. Pleasant sheep and big big wolf

    pid=3046">点击打开链接 题目:在一个N * M 的矩阵草原上,分布着羊和狼.每一个格子仅仅能存在0或1仅仅动物.如今要用栅栏将全部的狼和羊分开.问怎么放,栅栏数放的最少,求出 ...