DP综合练习
区间DP
P1775 石子合并(弱化版)
P1880 [NOI1995] 石子合并
- 环形区间DP:取模或将圆环转换成两倍线性区间
P1063 NOIP2006 提高组 能量项链
P1040 加分二叉树
矩形DP
P1387 最大正方形
- \(dp[i][j][k]\) 表示以\((i,j)\)为左上角,边长为\(k\)的正方形是否有效
- 其转移过程如图:
代码
P2701巨大牛棚
代码
P1736 创意吃鱼法
代码
其他DP
P1006 传纸条
- 采用\(i+j-1\)作为dp数组的第一维,斜向考虑
代码
P1004 [NOIP2000 提高组] 方格取数
思路和P1006类似,用\(i+j\)做dp的第一维
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 25;
int n;
int a[N][N];
int dp[N][N][N];
int main(){
cin >> n;
while(true){
int x, y, v;
cin >> x >> y >> v;
if(v == 0) break;
a[x][y] = v;
}
memset(dp, -0x3f, sizeof(dp));
dp[2][1][1] = a[1][1];
for(int i = 3; i <= 2 * n; i++){
for(int j = 1; j <= min(i - 1, n); j++){
for(int k = 1; k <= min(i - 1, n); k++){
dp[i][j][k] = max(max(dp[i - 1][j][k], dp[i - 1][j - 1][k]),
max(dp[i - 1][j][k - 1], dp[i - 1][j - 1][k - 1]));
if(j == k) dp[i][j][k] += a[j][i - j];
else dp[i][j][k] += a[j][i - j] + a[k][i - k];
}
}
}
cout << dp[2 * n][n][n] << endl;
return 0;
}
P1541 [NOIP2010 提高组] 乌龟棋
- 观察题面容易想到用剩余四种卡牌的数量作为状态,由这四个数字就能直接计算出棋子当前的位置,不需要再把位置作为一个维度
- 仔细审题再写代码,棋子从哪个位置开始,得分的初值是多少
代码
P1508 Likecloud-吃、吃、吃
代码
P1417 烹调方案
代码
P1782 旅行商的背包
P1858 多人背包
代码
P1158 导弹拦截
代码
P2066 机器分配
- 资源分配类动态规划(同时题目要求输出方案)
代码
P1855 榨取kkksc03
代码
P2722 USACO3.1 总分 Score Inflation
代码
P2639 USACO09OCT Bessie's Weight Problem G
代码
P1802 5 倍经验日
代码
USACO中的动态规划
P1470 USACO2.3 最长前缀 Longest Prefix
代码
P1472 USACO2.3 奶牛家谱 Cow Pedigrees
代码
[P1474 USACO2.3]Money System / [USACO07OCT]Cow Cash G
P1578 奶牛浴场
思路
一个“极大”的浴场一定四条边都受到限制,不能再扩展了