C++OJ题经验总结(竞赛)3

注意:本篇标红字段均是可纳为己用的经验条。
OJ题知识归属:

1、第一题:动态规划 -> 区间dp(基于区间的左右端点,分情况讨论)

2、第二题:动态规划 -> 区间dp(基于区间的左右端点,分情况讨论)

3、第三题:动态规划 -> 区间dp(基于区间上某⼀点,划分成左右区间讨论)(线形)

4、第四题:动态规划 -> 区间dp(基于区间上某⼀点,划分成左右区间讨论)(环形)
OJ题来源:洛谷

OJ题名:回文字串

OJ题归属:动态规划【区间dp】

解题算法:动态规划

经验总结:区间dp本质可以使用背包那种棋盘式填表顺序,但是由于特判比较多,所以一般使用区间dp特有的填表顺序(第一层:循环子串长度 1 -> n;第二层:循环左端点;右端点可以计算出来)。

此题的五板斧:

cpp 复制代码
#include<iostream>
#include<string>

using namespace std;

const int N = 1010;

string s;
int n;
int f[N][N];

int main()
{
	cin >> s;
	n = s.size();
	s = " " + s;

	for (int len = 1; len <= n; len++)
	{
		for (int left = 1; left + len - 1 <= n; left++)
		{
			int right = left + len - 1;
			if (s[left] == s[right]) f[left][right] = f[left + 1][right - 1];
			else f[left][right] = min(f[left + 1][right], f[left][right - 1]) + 1;
		}
	}

	cout << f[1][n] << endl;

	return 0;
}

OJ题来源:洛谷

OJ题名:Treats for the Cows(款待奶牛)

OJ题归属:动态规划【区间dp】

解题算法:动态规划

经验总结:区间dp本质特点之一:就是只对区间的左右两头端点进行操作。

cpp 复制代码
#include<iostream>

using namespace std;

const int N = 2010;

int n;
int a[N];
int f[N][N];

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];

	for (int len = 1; len <= n; len++)
	{
		for (int i = 1; i + len - 1 <= n; i++)
		{
			int j = i + len - 1;
			f[i][j] = max(f[i + 1][j] + a[i] * (n - len + 1), f[i][j - 1] + a[j] * (n - len + 1));
		}
	}

	cout << f[1][n] << endl;

	return 0;
}

OJ题来源:洛谷

OJ题名:石子合并(弱化版)

OJ题归属:动态规划【区间dp】

解题算法:动态规划 / 小小空间优化的动态规划

五板斧:

cpp 复制代码
#include<iostream>
#include<cstring>

using namespace std;

const int N = 310;

int n;
int a[N];
int sum[N];
int f[N][N];

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
	}

	memset(f, 0x3f3f3f3f, sizeof f);
	for (int i = 0; i <= n; i++) f[i][i] = 0;

	for (int len = 2; len <= n; len++)
	{
		for (int i = 1; i + len - 1 <= n; i++)
		{
			int j = i + len - 1;
			int t = sum[j] - sum[i - 1];

			for (int k = i; k < j; k++)
			{
				f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + t);
			}
		}
	}

	cout << f[1][n] << endl;

	return 0;
}

//小小空间优化一下
#include<iostream>
#include<cstring>

using namespace std;

const int N = 310;

int n;
int sum[N];
int f[N][N];

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int x; cin >> x;
		sum[i] = sum[i - 1] + x;
	}

	memset(f, 0x3f3f3f3f, sizeof f);
	for (int i = 0; i <= n; i++) f[i][i] = 0;

	for (int len = 2; len <= n; len++)
	{
		for (int i = 1; i + len - 1 <= n; i++)
		{
			int j = i + len - 1;
			int t = sum[j] - sum[i - 1];

			for (int k = i; k < j; k++)
			{
				f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + t);
			}
		}
	}

	cout << f[1][n] << endl;

	return 0;
}

OJ题来源:洛谷

OJ题名:石子合并

OJ题归属:动态规划【区间dp】

解题算法:"倍增"/复写 + 动态规划

经验总结:遇到环形的区间dp,可以通过 "倍增"/复写 将环形数据变成直线型数据;比如:环形数据:4、5、9、4 -> 线形数据:4、5、9、4、4、5、9、4。

五板斧:

cpp 复制代码
#include<iostream>
#include<cstring>

using namespace std;

const int N = 210;

int n, m;
int s[N];
int f[N][N]; //min
int g[N][N]; //max

int main()
{
	cin >> n;
	m = 2 * n;
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i];

		// "倍增"/复写
		s[i + n] = s[i];
	}

	//前缀和
	for (int i = 1; i <= m; i++) s[i] = s[i - 1] + s[i];

	//dp
	memset(f, 0x3f3f3f3f, sizeof f);
	memset(g, -0x3f3f3f3f, sizeof g);
	for (int i = 1; i <= m; i++) f[i][i] = g[i][i] = 0;

	for (int len = 1; len <= n; len++)
	{
		for (int i = 1; i + len - 1 <= m; i++)
		{
			int j = i + len - 1;
			int t = s[j] - s[i - 1];
			//枚举分割点
			for (int k = i; k < j; k++)
			{
				f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + t);
				g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + t);
			}
		}
	}

	int ret1 = 0x3f3f3f3f, ret2 = -0x3f3f3f3f;
	//枚举 环->线 可能情况的左端点
	for (int i = 1; i <= n; i++)
	{
		ret1 = min(ret1, f[i][i + n - 1]);
		ret2 = max(ret2, g[i][i + n - 1]);
	}

	cout << ret1 << endl << ret2 << endl;

	return 0;
}
相关推荐
geovindu15 分钟前
java:Abstract Factory Pattern
java·开发语言·后端·设计模式·抽象工厂模式·创建型模式
geovindu18 分钟前
java: Factory Method Pattern
java·开发语言·后端·设计模式·工厂方法模式·创建型模式
Tom@敲代码20 分钟前
js学习笔记-01
javascript·笔记·学习
z小猫不吃鱼26 分钟前
模型剪枝经典论文精读:Channel Pruning for Accelerating Very Deep Neural Networks
算法·机器学习·剪枝
m0_5870989938 分钟前
Qt,二进制文件读写建议
开发语言·qt
njsgcs43 分钟前
已知链中心距用节数算中间电机摆放位置 常量弧长 三链轮弦长模型算法
算法
爱敲代码的小鱼43 分钟前
springsecurity:
java·开发语言·数据库
秋田君1 小时前
QT_QT信号与槽机制
开发语言·数据库·qt
辞旧 lekkk1 小时前
【Qt】 系统相关:事件与定时器
开发语言·qt·学习·萌新
Wang's Blog1 小时前
Java框架快速入门: Spring Bean核心配置与实例化详解
java·开发语言·spring