horizonheart 2020-03-25
动态规划(DP)不是某种具体算法,而是一种思想。
核心在于:把大问题转化为小问题,利用小问题的解推断出大问题的解。
大事化小,小事化了 的思想
一、基本思想
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int f[maxn]; // 全局变量默认赋初值为0 int main() { int n; cin>>n; for(int i=1; i<=n; i++){ f[i]=f[i-1]+1; if(i-5>=0) f[i]=min(f[i], f[i-5]+1); if(i-11>=0) f[i]=min(f[i], f[i-11]+1); //printf("f[%d] = %d\n", i, f[i]); } printf("f[%d] = %d\n", i, f[i]); return 0; }
Coin_1
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int a[maxn]={0, 1, 3, 4, 7, 2, 6, 8, 5}, n=8; int f[maxn]; int main() { //f[1]=1; for(int x=1; x<=n; x++){ //for(int p=1; p<x; p++) for(int p=0; p<x; p++) // p要在x的前面;p从0开始,可以在max那一句把f[1]设成1 if(a[p]<a[x]) // a[x]可以接在a[p]的后面 f[x]=max(f[x], f[p]+1); printf("f[%d] = %d\n", x, f[x]); } return 0; }
LIS_1
2. 总结:
大问题和小问题的问题形式相同,问题规模不同
如果满足这个要求,那么我们遇到的每个问题,都可以很简洁地表达。我们把可能遇到的每种 “局面” 称为状态。
想用大事化小来做关于DP的题,必须先设计状态。 如何设计状态,来完整地描述当前遇到的局面?
例如上楼梯问题中:
设计完状态之后,只要能利用小状态的解求出大状态的解,就可以动手把题目做出来。
在前面三个例题中,我们都是先设计好状态,然后给出了一套用小状态推出大状态解的方法
从一个状态的解,得知另一个状态的解,我们称之为 “状态转移” 。这个转移式子称为 “状态转移方程”
设计转移有两种思路:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int f[maxn]; int main() { int n; cin>>n; f[0]=1; for(int i=0; i<=n; i++){ printf("f[%d] = %d\n", i, f[i]); f[i+1]+=f[i]; f[i+2]+=f[i]; } return 0; }
Stage_2
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int f[maxn]; int main() { int n; cin>>n; memset(f, 0x3f, sizeof(f)); f[0]=0; for(int i=0; i<=n; i++){ printf("f[%d] = %d\n", i, f[i]); f[i+1]=min(f[i+1], f[i]+1); f[i+5]=min(f[i+5], f[i]+1); f[i+11]=min(f[i+11], f[i]+1); } return 0; }
Coin_2
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int a[maxn]={0, 1, 3, 4, 7, 2, 6, 8, 5}, n=8; int f[maxn]; int main() { for(int i=1; i<=n; i++) f[i]=1; for(int x=1; x<=n; x++){ printf("f[%d] = %d\n", x, f[x]); for(int p=x+1; p<=n; p++) if(a[x]<a[p]) f[p]=max(f[p], f[x]+1); } return 0; }
LIS_2