三种基础dp
uva10003:
记忆化搜索
递推公式:dp[u][v] = min(dp[u][k]+dp[k][v]+a[v]-a[u], dp[u][v])
意思就是在某两个断点之间(0和m+1也算)选择断那个断点或不断,那么耗费自然是当前的全长
代码:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1005;
int n ,m;
int dp[maxn][maxn];
int a[55];
int Dp(int u, int v) {
if(dp[u][v] >= 0) return dp[u][v];
dp[u][v] = Dp(u, u+1) + Dp(u+1, v) + a[v]-a[u];
for(int i=u+2; i<v; i++) {
int temp = Dp(u, i) + Dp(i, v) + a[v]-a[u];
dp[u][v] = min(dp[u][v], temp);
}
return dp[u][v];
}
int main() {
while(scanf("%d", &n) != EOF && n) {
scanf("%d", &m);
for(int i=1; i<=m; i++) {
scanf("%d", &a[i]);
}
for(int i=0; i<m+1; i++)
for(int j=0; j<=m+1; j++) {
if(j-i == 1 || i-j==1)
dp[i][j] = 0;
else dp[i][j] = -1;
}
a[0] = 0;
a[m+1] = n;
printf("The minimum cutting is %d.\n", Dp(0, m + 1));
}
return 0;
}
uva675:完全背包
题意:给出五种硬币的面值以及兑换的钱数,那么问有几种组合方式
思路:
完全背包
贴一下Tanky Woo的程序人生的总结:
动态规划算法可分解成从先到后的4个步骤:
1. 描述一个最优解的结构;
2. 递归地定义最优解的值;
3. 以“自底向上”的方式计算最优解的值;
4. 从已计算的信息中构建出最优解的路径。
其中步骤1~3是动态规划求解问题的基础。如果题目只要求最优解的值,则步骤4可以省略。
背包的基本模型就是给你一个容量为V的背包
在一定的限制条件下放进最多(最少?)价值的东西
01背包(ZeroOnePack): 有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
1for i=1..N
2 for v=V..0
3 f[v]=max{f[v],f[v-c[i]]+w[i]};
完全背包(CompletePack): 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
for i=1..N
for v=0..V
f[v]=max{f[v],f[v-c[i]]+w[i]}
在次我们先来回忆下,01背包逆序的原因?是为了是max中的两项是前一状态值,这就对了。
那么这里,我们顺序写,这里的max中的两项当然就是当前状态的值了,为何?
因为每种背包都是无限的。当我们把i从1到N循环时,f[v]表示容量为v在前i种背包时所得的价值,这里我们要添加的不是前一个背包,而是当前背包。所以我们要考虑的当然是当前状态。
多重背包(MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
for(int i=0; i<nKind; ++i)
for(int j=0; j<bag[i]; ++j)//多循环了一层数量
for(int k=nValue; k>=value[i]; --k)
if(nMultiplePack[k] < nMultiplePack[k-value[i]]+weight[i])
nMultiplePack[k] = nMultiplePack[k-value[i]] + weight[i];
转载链接:http://www.wutianqi.com/?p=539
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 7500;
int n;
int t[] = {1, 5, 10, 25, 50};
int dp[maxn];
void Dp() {
dp[0] = 1;
for(int j=0; j<5; j++) {
for(int i=t[j]; i<=maxn; i++) {
dp[i] += dp[i-t[j]];
}
}
}
int main() {
Dp();
while(scanf("%d", &n)!=EOF) {
printf("%d\n", dp[n]);
}
return 0;
}
uva111
最长公共子序列
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
const int maxn = 25;
int first[maxn], second[maxn];
int d[maxn][maxn];
void dp() {
memset(d, 0, sizeof(d));
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(first[i] == second[j]) {
d[i][j] = d[i-1][j-1] + 1;
}
else {
d[i][j] = max(d[i-1][j], d[i][j-1]);
}
}
}
printf("%d\n", d[n][n]);
}
int main() {
scanf("%d", &n);
int temp;
for(int i=1; i<=n; i++) {
scanf("%d", &temp);
first[temp] = i;
}
while(scanf("%d", &temp) != EOF) {
second[temp] = 1;
for(int i=2; i<=n; i++){
scanf("%d", &temp);
second[temp] = i;
}
dp();
}
return 0;
}