给你一个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. solarwinds之网络发现

    1.  首先需要添加网络发现   2.  使用public   3.  添加主机   4.  网络地址选择   5.  默认下一步   6.  运行发现   7.  扫描结构如下   8.  下一步 ...

  2. 推箱子小游戏《格鲁的实验室》13关 - bfs最短路径

    下载了一款推箱子小游戏,第13关的时候怎么也破不了最佳纪录(最少步数是9而我们最好的方案是10步),因为数据比较小(6*8的方阵),所以写了个BFS来找最短路. 游戏的目标是把小黄人推到黄色球,小绿人 ...

  3. SAI / PS绘画一个卡通女孩详解

    本教程介绍使用SAI / PS绘画一个卡通女孩的教程 ,教程很详细,动起你的小手一起来试试吧! 软件下载:http://www.dongmansoft.com/xiazai.html 想要Get到更多 ...

  4. 被我忽略许久的set

    心塞,set一直是我忽略的一个数据结构 1.生成一个set: 1) set(iterable) 传入一个可以迭代的数据结构: eg:字符串;元组;列表,字典 2) {v1,v2,.......,vn} ...

  5. 计算机组成原理--64位CPU装载32位操作系统,它的寻址能力还是4GB吗?

    借由这个问题,今天我们就把 32 位 CPU.64 位 CPU.32 位操作系统.64 位操作系统之间的区别与联系彻底搞清楚.对于这个问题,博主也是一知半解了好长时间啊~ 基本概念 32位的CPU与6 ...

  6. Iterator(迭代器) 和generator

    数组是可迭代的 var a = []; console.dir(a); 发现这里有一个Symbol.iterator ,说明它是可迭代的. object 是不可以迭代的 var a = {} cons ...

  7. NOIp2018模拟赛四十

    今天太晚了...题解到时候补吧(flag立好) 成绩:100+0+0=100 感觉A题本质暴力贪心?C题一道水题我居然没做...亏爆 A:[agc011e]increasing numbers B:[ ...

  8. Python开发的简单记事本

    ---恢复内容开始---               主要是利用python 自带的tkinter 库    程序的基于python3.0以上 ,各个平台都可以使用包括linux ,windows , ...

  9. maven使用技巧

    转:MAVEN常用命令 Maven库: http://repo2.maven.org/maven2/ Maven依赖查询: http://mvnrepository.com/ Maven常用命令: 1 ...

  10. PHP设计模式(三)抽象工厂模式(Abstract Factory)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...