给你一个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. javaEE的开发模式

    1.什么是模式 模式在开发过程中总结出的“套路”,总结出的一套约定俗成的设计模式 2.javaEE经历的模式 model1模式: 技术组成:jsp+javaBean model1的弊端:随着业务复杂性 ...

  2. jquery动态表格,动态添加表格行

    转载收藏于:https://www.cnblogs.com/zhangqs008/archive/2013/05/09/3618459.html 效果图:   Html:<html> &l ...

  3. C# 将string 转换为二维码图片,然后转为base64字符串编码 。

    需在nuget 添加此dll ///content字符串 public static string GetQRCode(string content, int moduleSize = 9) { va ...

  4. [ZJOI2015]诸神眷顾的幻想乡 广义后缀自动机_DFS_语文题

    才知道题目中是只有20个叶子节点的意思QAQ.... 这次的广义后缀自动机只是将 last 设为 1, 并重新插入. 相比于正统的写法,比较浪费空间. Code: #include <cstdi ...

  5. 拉格朗日插值&&快速插值

    拉格朗日插值 插值真惨 众所周知$k+1$个点可以确定一个$k$次多项式,那么插值就是通过点值还原多项式的过程. 设给出的$k+1$个点分别是$(x_0,y_0),(x_1,y_1),...,(x_k ...

  6. HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)

    题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...

  7. 学习《数据科学入门》中文PDF+英文PDF+源代码

    数据科学是一个蓬勃发展.前途无限的行业,有人将数据科学家称为"21世纪头号性感职业".本书从零开始讲解数据科学工作,教授数据科学工作所必需的黑客技能,并带领读者熟悉数据科学的核心知 ...

  8. windows下命令行复制

    在CMD命令提示符窗口中点击鼠标右键,选择“标记”选项,然后按住鼠标左键不动,拖动鼠标标记想要复制的内容.标记完成以后请按键盘上的“回车”键

  9. 紫书 习题 8-13 UVa 10570 (枚举+贪心)

    我看到数据范围只有500, 第一反应枚举所有的可能,然后求出每种可能的最小次数. 但是不知道怎么求最小次数.我想的是尽量让一次交换可以让两个不在应该在的位置的数字 到原来应该在的位置的数字, 这样可以 ...

  10. System.IO.IsolatedStorage 使用 IsolatedStorageFileStream 存储信息

    在C#中还有一种叫做IsolatedStorage的存储机制,他存储信息的方式类似于我们的cookie, IsolatedStorage存储独立于每一个application,换句话说我们加载多个应用 ...