算法提高课-第一章-动态规划

摘花生

摘花生

#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
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值