动态规划
来源:互联网 发布:ubuntu syslog函数 编辑:程序博客网 时间:2024/05/20 20:03
1. split_1
问题描述:将一个数组v分成a,b两组,设最小难度为min(a中相邻元素之差绝对值和+b中相邻元素之差绝对值和)
输入描述:输入n(2 <= n <=2000),表示数组长度,接下来输入n个数。
5
1 5 6 2 1
输出描述:
3
ps:分成1 2 1和5 6两组时,最小难度为3=2+1
[分析]:
状态描述:dp[i][j]表示第i个元素分给a,第j个元素分给b时的最小难度和。
状态转移方程:要结合递归去表述,dp[la][lb] = min(solve(now, lb) + (la ? abs(v[now] - v[la]) : 0), solve(la, now) + (lb ? abs(v[now] - v[lb]) : 0)),now=max(la, lb)+1.
时间复杂度分析:实际上搜索过程就是一个满二叉树,高度为n,时间复杂度为2^n,因此在搜索过程中,用到了记忆搜索,整个过程会小于计算的最大时间复杂度。
#include <cstdio>#include <cstdlib>#include <iostream>using namespace std;#define MAX(a, b) ((a) > (b)? (a): (b))#define MIN(a, b) ((a) < (b)? (a): (b))const int maxn = 2e3 + 5;int n, v[maxn], dp[maxn][maxn];int solve(int la, int lb) { int now = MAX(la, lb) + 1; if(now == n + 1) return 0;//end if(dp[la][lb] != -1) return dp[la][lb];//已经求出此状态的最优解 return dp[la][lb] = MIN(solve(now, lb) + (la ? abs(v[now] - v[la]) : 0), solve(la, now) + (lb ? abs(v[now] - v[lb]) : 0)); //下一个元素,给a或者给b}int main() { while(~scanf("%d", &n)) {v[0] = -1;for(int i = 1; i <= n; i++) scanf("%d", &v[i]);memset(dp, -1, sizeof(dp));printf("%d\n", solve(0, 0));} return 0;}
2. split_2
问题描述:在第一题基础上,让两个数组的和的差绝对值最小。而且还要求出两个数组。
输入输出:同上
[分析]:严格上讲,不能算作dp(希望有能有更好的解法),而是递归求解。把每一个可能的情况,搜索一遍,找出最优解。
#include <cstdio>#include <cstdlib>#include <iostream>using namespace std;#define MAX(a, b) ((a) > (b)? (a): (b))#define MIN(a, b) ((a) < (b)? (a): (b))const int MAXN = 0x3f3f3f3f;//INT_MAX; const int maxn = 1e2 + 5;int n, v[maxn], dp[maxn][maxn], min_ans;int solve(int a[], int label[], int lb, int lc, int sumb, int sumc) { int now = MAX(lb, lc) + 1; if(now == n + 1) return abs(sumb - sumc); //if(dp[lb][lc] != -1) return dp[lb][lc];//完全搜索,求出最优值。 int res_b = solve(a, label, now, lc, sumb + a[now], sumc); int res_c = solve(a, label, lb, now, sumb, sumc + a[now]);// + abs(sumb - sumc - a[now]); is multi //cout << now << lb << lc << " " << " " << res_b << " " << res_c << endl; if (res_b < res_c) { if (res_b <= min_ans) { label[now] = 0; min_ans = res_b; } return res_b; } else { if (res_c <= min_ans) { label[now] = 1; min_ans = res_c; } return res_c; }}int splitToMin(int a[], int b[], int c[]) { memset(dp, -1, sizeof(dp)); int* label = (int*)malloc(sizeof(int) * (n + 1)); min_ans = MAXN; int ans = solve(a, label, 0, 0, 0, 0); int lb = 0, lc = 0; for (int i = 1; i <= n; ++i) { cout << label[i] << " " << a[i] << endl; if (label[i] == 0) b[lb++] = a[i]; else c[lc++] = a[i]; } free(label); return ans;}int main() { while(~scanf("%d", &n)) { v[0] = -1; for(int i = 1; i <= n; ++i) scanf("%d", &v[i]); int* b = (int*)malloc(sizeof(int) * (n + 1)); int* c = (int*)malloc(sizeof(int) * (n + 1)); printf("%d\n", splitToMin(v, b, c)); free(b); free(c); } return 0;}
3. 构造回文串
问题描述:给定一个数组,长度为n(2<= n <= 1000),插入一些数字,使得该序列为回文串。
输入描述:输入n,接下来输出n个数字
5
1 2 3 1 2
输出描述:
11
[分析]这道题与第一题类似,也是递归求解,即,每个状态都要考虑是添加左边还是添加右边的数字。同时,这里用到了“记忆化搜索”,不然就会超时。递归公式:
dp[l, r] = MIN(solve(l, r - 1) + a[r], solve(l + 1, r) + a[l])
- 动态规划!!!动态规划!!!
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 A,C,F , H
- 大数据分析中的 数据,大数据
- 泛型数组列表 ArrayList 用法总结
- 算法|动态规划问题
- forward和redirect的区别
- 动态规划
- 判断一棵树是否是平衡二叉树及其时间复杂度的优化
- position几种定位方式
- 先进软件开发技术与工具
- QFrame类
- 如何用Tensorflow训练模型成pb文件(二)——基于tfrecord的读取
- PAT (Basic Level) Practise (中文) 1051. 复数乘法 (15)
- [转载]VC 6.0中添加库文件和头文件
- FastJson