动态规划-过河卒
#include<bits/stdc++.h>
using namespace std;
int n, m, x, y;
int a[30][30];
long long dp[25][25];
int main(){
cin >> n >> m >> x >> y;
//标记障碍的位置
a[x][y] = 1, a[x + 1][y + 2] = 1, a[x + 2][y + 1] = 1;
if (x - 2 >= 0 && y - 1 >= 0) a[x - 2][y - 1] = 1;
if (x - 2 >= 0) a[x - 2][y + 1] = 1;
if (x - 1 >= 0) a[x - 1][y + 2] = 1;
if (y - 1 >= 0) a[x + 2][y - 1] = 1;
if (y - 2 >= 0) a[x + 1][y - 2] = 1;
if (x - 1 >= 0 && y - 2 >= 0) a[x - 1][y - 2] = 1;
//初始化
for (int i = 1; i <= n; i++){
if (a[i][0] == 1){
break;
}
dp[i][0] = 1;
}
for (int j = 1; j <= m; j++){
if (a[0][j] == 1){
break;
}
dp[0][j] = 1;
}
//递推
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (a[i][j] == 1){
continue;
}
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
printf("%lld\n", dp[n][m]);
return 0;
}
注意:注意数据范围,long long 输出的时候不要忘了用lld
long long dp[25][25];
printf("%lld\n", dp[n][m]);
动态规划-采药
就是一个简单的0-1背包的变式,不多赘述
//动态规划-采药
#include<bits/stdc++.h>
using namespace std;
int T, n;
int dp[20000], useTime[110], value[110];
//dp[j]表示在j时间内能取到的最大价值
int main(){
cin >> T >> n;
for (int i = 0; i < n; i++){
cin >> useTime[i] >> value[i];
}
for (int i = 0; i < n; i++){
for (int j = T; j >= useTime[i]; j--){
dp[j] = max(dp[j], dp[j - useTime[i]] + value[i]);
}
}
printf("%d\n", dp[T]);
return 0;
}
动态规划-装箱
同上
//动态规划-装箱问题
#include<bits/stdc++.h>
using namespace std;
int n, V;
int dp[21000], weight[50];
//dp[j]表示箱子容量为j时,能取到的最大价值
int main(){
cin >> V >> n;
for (int i = 0; i < n; i++){
cin >> weight[i];
}
for (int i = 0; i < n; i++){
for (int j = V; j >= weight[i]; j--){
dp[j] = max(dp[j], dp[j - weight[i]] + weight[i]);
}
}
printf("%d\n", V - dp[V]);
return 0;
}
动态规划-精卫填海
//动态规划-精卫填海
#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
int V, n, strengthSum;
int dp[N], strength[N], weight[N];
//dp[j]表示消耗体力j能搬运的最大容量
int main(){
cin >> V >> n >> strengthSum;
for (int i = 0; i < n; i++){
cin >> weight[i] >> strength[i];
}
//初始化
//递推
for (int i = 0; i < n; i++){
for (int j = strengthSum; j >= strength[i]; j--){
dp[j] = max(dp[j], dp[j - strength[i]] + weight[i]);
}
}
if (dp[strengthSum] < V){
printf("Impossible\n");
}
else {
for (int j = 1; j <= strengthSum; j++){
if (dp[j] >= V){
printf("%d\n", strengthSum - j);
break;
}
}
}
return 0;
}
动态规划-质数和分解
知识点:
完全背包,
求种类的动态规划,
预处理
以后求种类的动态规划题一定要想到以下状态转移方程:
dp[j] += dp[j - nums[i]];
//动态规划DP基础篇-质数和分解
#include<bits/stdc++.h>
using namespace std;
int n, k;
int dp[200], prime[200];
//dp[j]表示整数j可以分解成的不同的质数和总数
bool judgePrime(int x){
for (int i = 2; i <= sqrt(x); i++){
if (x % i == 0){
return 0;
}
}
return 1;
}
int main(){
for (int i = 2; i <= 200; i++){
if (judgePrime(i) == 1){
prime[++k] = i;
}
}
dp[0] = 1;
for (int i = 1; i <= k; i++){
for (int j = prime[i]; j <= 200; j++){
dp[j] += dp[j - prime[i]];
}
}
while (~scanf("%d", &n)){
printf("%d\n", dp[n]);
}
return 0;
}
总结
对于动态规划的题目,首先要明确dp数组的含义,这是重中之重,不然想要AC是不可能的,能求max问题就不要求min问题,动态规划有两个难点:
dp数组含义是否明确
状态转移方程是否正确
明确dp数组含义还是需要大量的经验的,还需要不断地刷dp题,至于状态转移方程的话,就需要自己画图举例总结了。