刷题日志(2)

写在前面的话:我也是初学,有些分析或知识会有错误,望各位大佬们指教

1:POJ 3280 Cheapest Palindrome (动态规划)

原题链接

  • 题意:
    给一个字符串,各个字母添加和删除所需花费的数额,问将字符串修改成回文,最低花费为多少。
  • 分析:
    对于字符串的操作一直不太熟悉,本题的动态规划分析也不太简单。如何用dp把状态记录?其实与区间有关系,用 dp [ i ] [ j ] 表示 ij 这一段字符串修改的最低费用。分析不同情况。
  1. s [ i ]s [ j ] 相同,那么就不用修改了,直接等于 s [ i + 1 ] [ j - 1 ]
  2. s [ i ]s [ j ] 不相同,那么分别有两个子串进行讨论,s [ i + 1 ] [ j ]s [ i ] [ j - 1 ],对于前项,我们需要讨论的是在前面删除 s [ i ] ,还是在末尾添加 s [ i ]。对于后项的讨论一样。
  • 代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<set>
#include<map>
#include<climits>
#include<cstdio>
#include<string>
#pragma warning(disable : 4996)
using namespace std;

int dp[2010][2010], add[30], del[30];
char s[2010];

int main() {
   
	int i, j, n, m, x, y, k;
	char ch;
	cin >> n >> m;
	cin >> s;
	for (i = 0; i < n; i++)
	{
   
		cin >> ch >> x >> y;
		add[ch - 'a'] = x;
		del[ch - 'a'] = y;
	}
	for (i = m - 1; i >= 0; i--)
	{
   
		dp[i][i] = 0;
		for (j = i + 1; j < m; j++)
		{
   
			dp[i][j] = INT_MAX;
			if (s[i] == s[j])
				dp[i][j] = dp[i + 1][j - 1];
			else
			{
   
				dp[i][j] = min(dp[i][j], min(dp[i + 1][j] + add[s[i] - 'a'], dp[i + 1][j] + del[s[i] - 'a']));
				dp[i][j] = min(dp[i][j], min(dp[i][j - 1] + add[s[j] - 'a'], dp[i][j - 1] + del[s[j] - 'a']));
			}
		}
	}
	cout << dp[0][m - 1] << endl;
	system("pause");
	return 0;
}

2:POJ 3046 Ant Counting (动态规划)

原题链接

  • 题意:
    给 n 种蚂蚁,每种蚂蚁有不同数量,问从s到e总共的组合数有多少。
  • 分析:
    经典的多重集组合数问题,关键是如何推出递推式。首先要设定dp数组代表什么,本题有n种物品,需要取k个,所以定义 dp [ i ] [ j ] 为取前 i 种中取 j 个的取法。那么假设第 i 种取 k 个,即前 i - 1 种取 j - k 种。那么有如下:
		for(int k = 0; k <= min(j, b[i]); k++)
			dp[i][j] += dp[i-1][j-k];

因为涉及三重循环,这样的复杂度可能会比较大,因此有如下优化:

		for(int k = 0; k <= min(j - 1, b[i]); k++)
			dp[i][j] += dp[i-1][j-k];
		dp[i][j] = dp[i][j] - dp[i-1][j-k-1] + dp[i-1][j];

相当于:

		dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1-b[i-1]];
  • 代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cmath>
#include<string>
#include <cstdio>
#include<stack>
#include<cstring>
#include<utility>
#include<climits>
#pragma warning(disable : 4996)
using namespace std;

int b[1010];
int dp[1005][100005];
const int MOD = 1000000;

int main() {
   
	int n, m, s, e, i, j, k;
	cin >> n >> m >> s >> e;
	for (i = 0; i < m; i++)
	{
   
		cin >> k;
		b[k - 1]++;
	}
	for (i = 0; i <= n; i++)
		dp[i][0] = 1;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= e; j++)
		{
   
			if (j - b[i - 1] - 1 >= 0)
				dp[i][j] = (dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - b[i - 1] - 1] + MOD) % MOD;
			else
				dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % MOD;
		}
	int sum = 0;
	for (i = s; i <= e; i++)
	{
   
		sum += dp[n][i];
		sum %= MOD;
	}
	cout << sum << endl;
	system("pause");
	return 0;
}

3: POJ 3614 Sunscreen (贪心 + 优先队列)

原题链接

  • 题意:
    有n头牛,他们需要的防晒霜度数区间分别为 xi-yi ,有m瓶防晒霜,分别有不同的数量和度数,问最多能让多少头牛涂上防晒霜。
  • 分析:
    先将防晒霜按度数从小到大排序,然后尽可能把度数小的留给需求区间相对应小的牛。关键是如何处理牛的排序,是按 xi 排序,还是 yi 排序。运用贪心的思想,先按 xi 从小到大排序,然后选择相对应的防晒霜,取所有 xi 低于该度数的牛,然后再从中取这群牛中 yi 最小的,这里用优先队列进行操作,达到贪心的目的。
  • 代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值