摘花生
#include<bits/stdc++.h>
using namespace std;
int dp[110][110], a[110][110];
int main()
{
int T;
cin >> T;
while (T -- ) {
memset (dp, 0, sizeof dp);
int n, m;
cin >> n >> m;
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= m;j ++)
cin >> a[i][j];
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= m;j ++)
dp[i][j] = a[i][j] + max (dp[i-1][j], dp[i][j-1]);
cout << dp[n][m] << endl;
}
return 0;
}
方格取数
附另外一种代码:(也可以换成三维dp)
#include<bits/stdc++.h>
using namespace std;
const int N = 20;
// dp[i][j][p][q] 表示A从左上角到ij,B从左上角到pq的最大值 (默认要满足i+j=p+q)
int dp[N][N][N][N], a[N][N];
int n, x, y, v;
int main()
{
cin >> n;
while (cin >> x >> y >> v && x && y && v)
a[x][y] = v;
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++)
for (int p = 1;p <= n;p ++)
{
int q = i+j-p;
if (q <= 0 || q > n) continue;
dp[i][j][p][q] += a[i][j] + (i == p && j == q ? 0 : a[p][q]);
dp[i][j][p][q] += max (max (dp[i-1][j][p-1][q],
dp[i][j-1][p][q-1]),
max (dp[i-1][j][p][q-1],
dp[i][j-1][p-1][q]));
}
cout << dp[n][n][n][n] << endl;
return 0;
}
最低通行费
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f, N = 110;
int dp[N][N], a[N][N];
int n;
int main()
{
memset (dp, 0x3f, sizeof dp);
dp[0][1] = dp[1][0] = 0;
cin >> n;
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++)
cin >> a[i][j];
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++) {
dp[i][j] = min (a[i][j] + min (dp[i-1][j], dp[i][j-1]), INF);
}
cout << dp[n][n] << endl;
return 0;
}
最长上升子序列模板与优化后的模板
怪盗基德的滑翔翼
登山
合唱队形
与“登山”问题代码相同,只是改一下输出即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int f[N], a[N];
int main()
{
int n;
cin >> n;
for (int i = 1;i <= n;i ++) cin >> a[i];
int ans = n;
for (int k = 1;k <= n;k ++) {
int ans1 = n, ans2 = n;
for (int i = 1;i <= k;i ++) {
f[i] = 1;
for (int j = 1;j < i;j ++)
if (a[i] > a[j])
f[i] = max (f[i], f[j] + 1);
ans1 = min (ans1, k - f[i]);
}
for (int i = k;i <= n;i ++) {
f[i] = 1;
for (int j = k;j < i;j ++)
if (a[i] < a[j])
f[i] = max (f[i], f[j] + 1);
ans2 = min (ans2, n-k+1-f[i]);
}
ans = min (ans, ans1 + ans2);
}
cout << ans << endl;
return 0;
}
友好城市
最大上升子序列和
导弹拦截
int binary_search_down (int x) { // 等价于 upper_bound (d+1, d+1+len, x, greater<int>() ) - d
int m, l = 1, r = len;
while (l < r) {
m = l + r >> 1;
if (d[m] < x) r = m;
else l = m + 1;
}
return l;
}
int binary_search_up (int x) { // 等价于 lower_bound (d+1, d+1+len, x) - d
int m, l = 1, r = len;
while (l < r) {
m = l + r >> 1;
if (d[m] >= x) r = m;
else l = m + 1;
}
return l;
}
最长公共上升子序列
本题没有free题目测评。
#include<bits/stdc++.h>
using namespace std;
const int N = 3010;
int n, ans;
int a[N], b[N], f[N][N];
int main()
{
cin >> n;
for (int i = 1;i <= n;i ++) cin >> a[i];
for (int i = 1;i <= n;i ++) cin >> b[i];
for (int i = 1;i <= n;i ++) {
for (int j = 1;j <= n;j ++) {
f[i][j] = f[i-1][j];
if (a[i] == b[j]) {
f[i][j] = 1;
for (int k = 1;k < j;k ++)
if (b[k] < b[j])
f[i][j] = max (f[i][j], f[i-1][k] + 1); // y总这里应该是讲错了,f[i-1][k] + 1
}
}
}
for (int i = 1;i <= n;i ++)
ans = max (ans, f[n][i]);
cout << ans << endl;
return 0;
}
/*
4
2 2 1 3
2 1 2 3
2
*/
优化成两重循环
#include<bits/stdc++.h>
using namespace std;
const int N = 3010;
int n, ans;
int a[N], b[N], f[N][N];
int g[N][N]; // g[i][j]表示所有满足a[i] > b[j]的所有f[i-1][j]+1的最大值
int main()
{
cin >> n;
for (int i = 1;i <= n;i ++) cin >> a[i];
for (int i = 1;i <= n;i ++) cin >> b[i];
for (int i = 1;i <= n;i ++) {
g[i][0] = 1;
for (int j = 1;j <= n;j ++) {
f[i][j] = f[i-1][j];
if (a[i] == b[j]) f[i][j] = max (f[i][j], g[i][j-1]);
g[i][j] = g[i][j-1];
if (b[j] < a[i]) g[i][j] = max (g[i][j], f[i-1][j] + 1);
}
}
for (int i = 1;i <= n;i ++)
ans = max (ans, f[n][i]);
cout << ans << endl;
return 0;
}
/*
4
2 2 1 3
2 1 2 3
2
*/
将g
数组优化为变量:
#include<bits/stdc++.h>
using namespace std;
const int N = 3010;
int n, ans;
int a[N], b[N], f[N][N];
int main()
{
cin >> n;
for (int i = 1;i <= n;i ++) cin >> a[i];
for (int i = 1;i <= n;i ++) cin >> b[i];
for (int i = 1;i <= n;i ++) {
int maxv = 1;
for (int j = 1;j <= n;j ++) {
f[i][j] = f[i-1][j];
if (a[i] == b[j]) f[i][j] = max (f[i][j], maxv);
if (b[j] < a[i]) maxv = max (maxv, f[i-1][j] + 1);
}
}
for (int i = 1;i <= n;i ++)
ans = max (ans, f[n][i]);
cout << ans << endl;
return 0;
}
/*
4
2 2 1 3
2 1 2 3
2
*/