PAT第十一章专题复习
-
本专题还需要多重复几遍,很不熟悉!!
-
最长公共子序列
-
变形:允许元素重复
-
A 1045 Favorite Color Stripe (30 分)
-
思路:
①本题一开始想到的是用最长不下降子序列做。
②也可以用最长公共子序列来做,不过状态转移方程是经过变形的。
//不允许元素重复的状态转移方程 if(a[i] == b[j]){ dp[i][j] = dp[i-1][j-1] + 1; }else{ dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } //允许元素重复的状态转移方程 if(a[i] == b[j]){ dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + 1; }else{ dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } //两者边界一样 dp[i][0] = dp[0][j] = 0;
-
代码实现
#include<bits/stdc++.h> using namespace std; const int maxc = 210; const int maxn = 10010; int n, m, L; int a[maxc], b[maxn]; int dp[maxc][maxn]; int main(){ cin >> n >> m; for(int i = 1; i <= m; i++){ cin >> a[i]; } cin >> L; for(int i = 1; i <= L; i++){ cin >> b[i]; } //边界 for(int i = 0; i <= m; i++)dp[i][0] = 0; for(int i = 0; i <= L; i++)dp[0][i] = 0; //状态转移方程 for(int i = 1; i <= m; i++){ for(int j = 1; j <= L; j++){ if(a[i] != b[j]){ dp[i][j] = max(dp[i-1][j], dp[i][j-1]); }else{ dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + 1; } } } cout << dp[m][L]; return 0; }
-
-
-
背包问题
-
PAT A 1068 【01背包】(很难,需要再琢磨多遍】
-
思路:
①选取几个数等于某一个值,可以看出来是01背包模型。
②难点在于如何运用这个模型。本题的c[i] = w[i]; 然后需要将w[i]按从大到小的顺序排序来满足输出的答案为最小字典序的条件。
③排好序之后,就套用01背包模板,同时需要有一个二维变量choice[i] [v]来记录当背包容量为v时是否选择第i件物品,选择值为1,反之为0.
④算完所有的dp数组值之后,判断dp[m]是否等于m,也就是题目中条件是否能够凑出等于m值的硬币选项。 这一点不同于01背包模型中,遍历所有dp数组寻找最大dp值来表示最大价值。是一个变形
⑤如果有dp[m] = m,接下来就寻找最优解。因为要输出字典序小的答案,所以需要倒序来遍历choice[i] [v]数组,当choice数组值为1的时候,就将flag数组记为1(flag数组用来表示最终答案选择哪几个)。最后遍历flag数组,将值为1的选项输出w[i]即硬币面额。
-
难点:对于背包问题的状态转移过程理解还不够透彻,另外如何输出最小字典序也不清楚。
-
代码实现
#include<bits/stdc++.h> using namespace std; int n, m; int w[10010], dp[10010], flag[10010] = {0}; int choice[10010][110]; bool cmp(int a, int b){ return a > b; } int main(){ cin >> n>> m; for(int i = 1; i <= n; i++){ cin >> w[i]; } //逆序排序,这样配合后面的倒序枚举v,可以将字典序小的 //选项排在前面 sort(w + 1, w + n + 1, cmp); //01背包模型 for(int i = 1; i <= n; i++){ for(int v = m; v >= w[i]; v--){ if(dp[v] <= dp[v-w[i]] + w[i]){ dp[v] = dp[v-w[i]] + w[i]; choice[i][v] = 1; //值为1表示选择第i件物品 } else choice[i][v] = 0;//值为0表示不选择第i件物品 } } if(dp[m] != m){//不相等表明不能恰好等于m printf("No Solution"); } else{ //记录最优路径 int k = n, v = m, num = 0, index = 0; while(k >= 0){ if(choice[k][v] == 1){ flag[k] = 1; //选择第k个 v -= w[k]; num++; } k--; } for(int i = n; i >= 1; i--){ if(flag[i] == 1){ printf("%d", w[i]); index++; if(num != index)printf(" "); } } } return 0; }
-
-