本文主要是介绍AtCoder Educational DP Contest,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
A - Frog 1
大意
有块石头,第块石头的高度为。从石头跳到石头的花费是。
一只青蛙在石头上,每次可以跳步或步,请问跳到石头的最小代价是多少?
思路
设,为青蛙跳到第号石头时的最小代价。
每一个点都可以由前两个点转移而来,因此状态转移方程为:
边界可由定义得出:。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n;cin >> n;vector<int> a(n + 1), dp(n + 1, 0);for(int i = 1; i <= n; i++) cin >> a[i];auto cost = [&](int i, int j) -> int{int ret = a[i] - a[j];if(ret < 0) ret = -ret;return ret;};dp[2] = cost(1, 2);for(int i = 3; i <= n; i++)dp[i] = min(dp[i - 1] + cost(i, i - 1), dp[i - 2] + cost(i, i - 2));cout << dp[n] << endl;return 0;
}
B - Frog 2
大意
有块石头,第块石头的高度为。从石头跳到石头的花费是。
一只青蛙在石头上,每次可以跳~步,请问跳到石头的最小代价是多少?
思路
和上一题一样,设,为青蛙跳到第号石头时的最小代价。
每一个点都可以由前个点转移而来(除了的情况),因此状态转移方程为:
边界为。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, k;cin >> n >> k;vector<int> a(n + 1), dp(n + 1, INF);for(int i = 1; i <= n; i++) cin >> a[i];auto cost = [&](int i, int j){int ret = a[i] - a[j];return (ret > 0? ret: -ret);};dp[1] = 0;for(int i = 2; i <= n; i++){for(int j = max(1ll, i - k); j < i; j++) dp[i] = min(dp[i], dp[j] + cost(i, j));}cout << dp[n] << endl;
}
C - Vacation
大意
有天时间和种活动。每天只能进行一个活动,且相邻两天不能做相同的活动。
第天做三种活动分别可以获得点快乐值,求这天里最大可以获得多少点快乐值。
思路
设为考虑到第天,且第天进行活动的最大值。
由于相邻两天不能做相同的活动,所以只能从另外两个状态中的最大值转移过来。、
因此,状态转移方程为:
边界为,答案为。
时间复杂度。
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long longsigned main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n;cin >> n;vector<int> a(n + 1), b(n + 1), c(n + 1);vector<int> dp1(n + 1, 0), dp2(n + 1, 0), dp3(n + 1, 0);for(int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> c[i];for(int i = 1; i <= n; i++){dp1[i] = max(dp2[i - 1], dp3[i - 1]) + a[i];dp2[i] = max(dp1[i - 1], dp3[i - 1]) + b[i];dp3[i] = max(dp1[i - 1], dp2[i - 1]) + c[i];}cout << max(dp1[n], max(dp2[n], dp3[n])) << endl;
}
D - Knapsack 1
大意
有件物品和一个承重量为千克的袋子。
第件物品的重量为千克,价值为元。
现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。
思路
经典01背包问题,按照01背包的解法做即可。
注意需要long long。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long longsigned main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m;cin >> n >> m;vector<int> w(n + 1), v(n + 1), dp(m + 1, 0);for(int i = 1; i <= n; i++) cin >> w[i] >> v[i];for(int i = 1; i <= n; i++)for(int j = m; j >= w[i]; j--)dp[j] = max(dp[j], dp[j - w[i]] + v[i]);cout << dp[m] << endl;return 0;
}
E - Knapsack 2
大意
有件物品和一个承重量为千克的袋子。
第件物品的重量为千克,价值为元。
现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。
思路
很大,直接套用01背包计算,时间和空间肯定一定炸。
由于很小,我们可以转换思路,设为价值为 的最小重量,这样就不会炸了。
最后从大到小遍历,找到符合的直接输出。
时间复杂度,其中为的取值范围,
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m;cin >> n >> m;vector<int> w(n + 1), v(n + 1);int sum = 0;for(int i = 1; i <= n; i++){cin >> w[i] >> v[i];sum += v[i];}vector<int> dp(sum + 1, INF);dp[0] = 0;for(int i = 1; i <= n; i++)for(int j = sum; j >= v[i]; j--)dp[j] = min(dp[j], dp[j - v[i]] + w[i]);for(int j = sum; j >= 0; j--)if(dp[j] <= m){cout << j << endl;break;}return 0;
}
F - LCS
题意
给定两个字符串,输出它们的任意一个最长公共子序列。
思路
求LCS时将最优策略保存下来,用来表示状态是否和有关,来表示状态是否和有关。
根据和,就可以递归输出方案。
代码
#include <iostream>
#include <vector>
using namespace std;
int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);string x, y;cin >> x >> y;int n = x.size(), m = y.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1));vector<vector<int>> f1(n + 1, vector<int>(m + 1));vector<vector<int>> f2(n + 1, vector<int>(m + 1));auto lcs = [&](string a, string b, int n, int m) -> void{for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){if(a[i - 1] == b[j - 1]){dp[i][j] = dp[i - 1][j - 1] + 1;f1[i][j] = 1;f2[i][j] = 1;}else if(dp[i - 1][j] > dp[i][j - 1]){dp[i][j] = dp[i - 1][j];f1[i][j] = 1;}else{dp[i][j] = dp[i][j - 1];f2[i][j] = 1;}}};string ans = "";auto dfs = [&](auto self, string a, string b, int i, int j) -> void{if(i == 0 || j == 0) return;self(self, a, b, i - f1[i][j], j - f2[i][j]);if(a[i - 1] == b[j - 1]) ans.push_back(a[i - 1]);};lcs(x, y, n, m);dfs(dfs, x, y, n, m);cout << ans << endl;}
这篇关于AtCoder Educational DP Contest的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!