DP
一、区间DP
1. 石子合并
(1) 相邻成圈取🏐:这道让我一直纠结于dp的最优子结构和贪心的局部最优,实际上到现在还不太能讲清楚,不过,像田忌赛马一样?
思路是:把圈石头变成直石头,以两堆合并到n堆合并为阶段,从l堆到r堆合并为状态,判断用k在l r之间分割并判断为决策。
1 #include<bits/stdc++.h> 2 #define mem(a) memset(a,0,sizeof(a)) 3 #define mem1(a) memset(a,-1,sizeof(a)) 4 #define fio ios::sync_with_stdio(false);cin.tie(0) 5 #define ll long long 6 #define mp make_pair 7 #define inf 0x3f3f3f3f 8 const int N=305; 9 const int M=1e3+10; 10 const ll mod=998244353; 11 using namespace std; 12 int m,n,a[N],dpmax[N][N],dpmin[N][N],sum[N]; 13 int main() 14 { 15 fio; 16 cin>>n; 17 memset(dpmin,0x3f,sizeof(dpmin)); 18 mem1(dpmax); 19 for(int i=1;i<=n;i++) 20 { 21 cin>>a[i]; 22 a[n+i]=a[i]; 23 sum[i]=sum[i-1]+a[i]; 24 dpmax[i][i]=dpmin[i][i]=0; 25 } 26 for(int i=n+1;i<=2*n-1;i++) 27 { 28 sum[i]=sum[i-1]+a[i]; 29 dpmax[i][i]=dpmin[i][i]=0; 30 } 31 32 for(int i=2;i<=n;i++) 33 { 34 for(int l=1;l+i-1<=2*n-1;l++) 35 { 36 int r=l+i-1; 37 for(int k=l;k<r;k++) 38 { 39 dpmax[l][r]=max(dpmax[l][r],dpmax[l][k]+dpmax[k+1][r]+sum[r]-sum[l-1]); 40 dpmin[l][r]=min(dpmin[l][r],dpmin[l][k]+dpmin[k+1][r]+sum[r]-sum[l-1]); 41 } 42 } 43 } 44 int mn=inf,mx=-inf; 45 for(int i=1;i<=n;i++) 46 { 47 mn=min(mn,dpmin[i][i+n-1]); 48 mx=max(mx,dpmax[i][i+n-1]); 49 } 50 cout<<mn<<endl<<mx<<endl; 51 return 0; 52 }
2. 租用游艇
也是把从l到r的费用问题,转为比较从l到k+从k到r。
洛谷P1359 只要求求从1到n的最小花费,下面的代码包括从l到r和记录最优中介点(用s[][]记录,最后打印就递归就行)
P1359 租用游艇3. 矩阵连乘:即a的列等于b的行,多个矩阵相乘时,其行列分别对应首尾矩阵,矩阵相乘次数是m*n*k。题目一般给出n个数,则代表n-1个矩阵,a[0],a[1]是第一个矩阵的行和列, a[1]也是第二个矩阵的行。也是在l和r中间找一个k,这样就有三个矩阵连乘的值。因为无论怎么分,最后这两个被k分隔的矩阵还是要乘起来,即a[l-1] * a[r] * a[k] 注意l-1,即l矩阵的行

poj1651就是一道矩阵连乘题
poj 1651
二、背包问题
(1) 01背包
1 int rec(int i,int j) 2 { 3 if(dp[i][j]>=0) return dp[i][j]; 4 int ans; 5 if(i==n) //没有剩余物品 6 ans=0; 7 else if(j<w[i]) //钱不够 8 ans=rec(i+1,j); 9 else 10 ans=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]); 11 return dp[i][j]=ans; 12 } 13 void solve() 14 { 15 memset(dp,-1,sizeof(dp)); 16 printf("%d\n",rec(0,W)); 17 } 18
1 void solve1() //逆向 2 { 3 //dp[i][j]表示从第i个物品之后的物品中挑选花费总和小于j的物品 4 for(int i=n-1;i>=0;i--) 5 { 6 for(int j=0;j<=W;j++) 7 { 8 if(j<w[i]) 9 dp[i][j]=dp[i+1][j]; 10 else 11 dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]); 12 } 13 } 14 printf("%d\n",dp[0][W]); 15 } 16 17 void solve2() //正向 18 { 19 //dp[i][j]表示从前i个物品中选出总花费不超过j的物品时总价值的最大值 20 for(int i=0;i<n;i++) 21 { 22 for(int j=0;j<=W;j++) 23 { 24 if(k<w[i]) 25 dp[i+1][j]=dp[i][j]; 26 else 27 dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]+v[i]); 28 } 29 } 30 printf("%d\n",dp[n][W]); 31 } 32 33 void solve3() //两种状态 34 { 35 //dp[i][j]表示从前i个物品中选出总花费不超过j的物品时总价值的最大值 36 /* 37 状态转移为从"前i个物品中选取总重量不超过j时的状态"向 38 "前i+1个物品中选取总重量不超过j"和 39 "从前i+1个物品中选取总重量不超过j+w[i]时的状态"的转移: 40 */ 41 for(int i=0;i<n;i++) 42 { 43 for(int j=0;j<=W;j++) 44 { 45 dp[i+1][j]=max(dp[i+1][j],dp[i][j]); 46 if(j+w[i]<=W) 47 dp[i+1][j+w[i]]=max(dp[i+1][j+w[i]],dp[i][j+w[i]-w[i]]+v[i]); 48 } 49 } 50 printf("%d\n",dp[n][W]); 51 }
//两种方法都是O(nW)
二、LCS
1.可以参考《趣学算法》或这篇🥟
找到状态dp[i]][j]记录a中从0到i和b中从0到j最小公共子序列的长度。有三种可能,标出来就行。如果要求输出具体是哪几个字符,可以再开一个数组,记录是三种情况中的哪一种
如这题🍓
1 #include<bits/stdc++.h> 2 #include<iostream> 3 #include<stack> 4 #include<algorithm> 5 #include<cstdio> 6 #include<cmath> 7 #include<cstring> 8 #define fio ios::sync_with_stdio(false);cin.tie(0) 9 #define mem(a) memset(a,0,sizeof(a)) 10 #define memm(a) memset(a,inf,sizeof(a)) 11 #define ll long long 12 #define ld long double 13 #define uL unsigned long long 14 #define pb push_back 15 #define inf 0x3f3f3f3f 16 using namespace std; 17 const int N=1e3+5; 18 const int M=1e9+5; 19 int n,m,t,x,a[N],q,y,b[N][N],vis[N],dp[N][N]; 20 string s,d; 21 void print(int i,int j) 22 { 23 if(i==0||j==0) return; 24 if(b[i][j]==1) 25 { 26 print(i-1,j-1); 27 cout<<s[i-1]; 28 } 29 else if(b[i][j]==2) 30 print(i-1,j); 31 else if(b[i][j]==3) 32 print(i,j-1); 33 34 } 35 int main() 36 { 37 fio; 38 cin>>s>>d; 39 int len1=s.size(),len2=d.size(); 40 for(int i=1;i<=len1;i++) 41 { 42 for(int j=1;j<=len2;j++) 43 { 44 //if(i==0||j==0) dp[i][j]=0,b[i][j]=0; 45 46 if(s[i-1]==d[j-1]) dp[i][j]=dp[i-1][j-1]+1,b[i][j]=1; 47 else 48 { 49 if(dp[i-1][j]>dp[i][j-1]) 50 dp[i][j]=dp[i-1][j],b[i][j]=2; 51 else 52 dp[i][j]=dp[i][j-1],b[i][j]=3; 53 } 54 55 } 56 } 57 print(len1,len2); 58 59 60 return 0; 61 }
三、未归类
1. 编辑距离:即将一个字符串变换为另一个字符串所需要的最小编辑操作。跟LCS很像,也是三种可能,dp[i-1][j]+1就是

浙公网安备 33010602011771号