棋盘型DP
来源:互联网 发布:在家网络兼职的工作 编辑:程序博客网 时间:2024/05/16 18:37
1.过河卒(NOIP2002普及组)
http://codevs.cn/problem/1010/
算法:状态转移就是向下和向右两个方向,方程很好写。
PS:用记忆化搜索更方便一些。
代码:
#include<bits/stdc++.h>#define MAX_N 20using namespace std;long long f[MAX_N][MAX_N];int n, m, X, Y;long long search(int x, int y){ if ((x > n) || (y > m)) return 0; if ((abs(x-X) == 1) && (abs(y-Y) == 2)) return 0; if ((abs(x-X) == 2) && (abs(y-Y) == 1)) return 0; if ((x == X) && (y == Y)) return 0; if (f[x][y] != 0) return f[x][y]; f[x][y] = search(x+1, y) + search(x, y+1); return f[x][y];}int main(){ cin >> n >> m >> X >> Y; memset(f, 0, sizeof(f)); f[n][m] = 1; cout << search(0, 0); return 0;}
2.骑士游历(NOIP1997)
http://codevs.cn/problem/1219/
算法:状态转移四个方向,用常量数组dx和dy实现x和y坐标的变化。
PS:还是写成记忆化更方便一些。
代码:
#include<bits/stdc++.h>#define MAX_N 51using namespace std;const int dx[4] = {1, 1, 2, 2};const int dy[4] = {2, -2, 1, -1};int n, m;int x1, yy1, x2, y2;long long f[MAX_N][MAX_N];long long search(int x, int y){ if (x > x2) return 0; if ((y < 1) || (y > m)) return 0; if (f[x][y] != 0) return f[x][y]; for (int k = 0; k < 4; k++) f[x][y] += search(x+dx[k], y+dy[k]); return f[x][y];}int main(){ cin >> n >> m; cin >> x1 >> yy1 >> x2 >> y2; memset(f, 0, sizeof(f)); f[x2][y2] = 1; cout << search(x1, yy1); return 0;}
3.传纸条(NOIP2008提高组)
http://codevs.cn/problem/1169/
方程:
f[i][j][k][l]=max{f[i-1][j][k-1][l], f[i-1][j][k][l-1], f[i][j+1][k-1][l], f[i][j+1][k][l-1]}+h[i][j]+h[k][l]
首先我们认为第二个纸条也是从(1,1)出发。
f[i][j][k][l]同时描述两个纸条的传递,含义是第一个纸条到(i,j)位置,第二个纸条到(k,l)位置的最优解。
算法:
这是一个多线程的动态规划。不难发现i,j,k,l之间有这样的关系i+j=k+l,这样就可以把四维降成三维,减少时空复杂度。
代码:
#include<bits/stdc++.h>#define MAX_N 51using namespace std;int n, m;int h[MAX_N][MAX_N];int f[MAX_N][MAX_N][MAX_N];int search(int x1, int y1, int x2, int y2){ if ((x1 == n) && (y1 == m) && (x2 == n) && (y2 == m)) return 0; if ((x1 > n) || (y1 > m) || (x2 > n) || (y2 > m)) return 0; if ((x1 == x2) && (y1 == y2)) return 0; if (f[x1][y1][x2] != 0) return f[x1][y1][x2]; f[x1][y1][x2] = max(f[x1][y1][x2], search(x1+1, y1, x2+1, y2)); f[x1][y1][x2] = max(f[x1][y1][x2], search(x1+1, y1, x2, y2+1)); f[x1][y1][x2] = max(f[x1][y1][x2], search(x1, y1+1, x2+1, y2)); f[x1][y1][x2] = max(f[x1][y1][x2], search(x1, y1+1, x2, y2+1)); f[x1][y1][x2] += h[x1][y1] + h[x2][y2]; return f[x1][y1][x2];}int main(){ cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> h[i][j]; memset(f, 0, sizeof(f)); cout << search(1, 2, 2, 1); return 0;}
4.数字三角形
http://codevs.cn/problem/1220/
方程:
f[i][j] = max{[i-1][j], f[i-1][j-1]}+a[i][j]
PS:很经典的递推。
代码:
#include<bits/stdc++.h>#define MAX_N 101using namespace std;int n;int a[MAX_N][MAX_N], f[MAX_N][MAX_N];int main(){ cin >> n; memset(a, 0 ,sizeof(a)); for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) cin >> a[i][j]; f[0][1] = -1; f[0][0] = -1; for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) { f[i][j] = max(f[i][j], f[i-1][j]); f[i][j] = max(f[i][j], f[i-1][j-1]); f[i][j] += a[i][j]; } int res = f[n][1]; for (int i = 1; i <= n; i++) res = max(res, f[n][i]); cout << res; return 0;}
0 0
- 棋盘型DP
- [poj 1191] 棋盘分割 划分型DP
- [poj 2948] Martian Mining 棋盘型DP
- codevs1219 骑士游历 棋盘型DP
- <棋盘型DP> noip 2008 传纸条
- DP 棋盘覆盖 二
- 棋盘分割----dp
- 棋盘分割----POJ1191----DP
- POJ1191--棋盘分割--DP
- poj1191-dp棋盘分割
- 棋盘寻宝【dp】
- 棋盘寻宝变种【dp】
- POJ1191(棋盘分割DP)
- HDU4826 - Labyrinth(棋盘DP)
- poj1191--棋盘分割(dp)
- poj1191 棋盘分割 dp
- 【棋盘类DP】
- pku1191 棋盘分割 DP
- vc工程加入已有的类出现的问题
- Gradle for Android 第三篇( 依赖管理 )
- C#使用指定的字符替换除首尾字符外的字符
- Python 日期和时间学习
- iTest微服务测试经验总结(第一版)
- 棋盘型DP
- signal(SIGCHLD, SIG_IGN)和signal(SIGPIPE, SIG_IGN);
- 7.1 Tomcat学习(日志记录器Logger)
- Redis命令总结
- 11.3添加一组元素
- C++语言的一些问题
- 来自京东、唯品会对微服务编排、API网关、持续集成的实践分享(上)
- date: 无法设置日期: 不允许的操作
- eclipse快捷键