【每日一题 | 2025年5.19 ~ 5.25】动态规划相关题

在这里插入图片描述

个人主页:Guiat
归属专栏:每日一题

在这里插入图片描述

正文

1. 【5.19】P1130 红牌

题目链接:https://www.luogu.com.cn/problem/P1130

【分析】
二维动态规划问题,从倒数第2步考虑,取两种方案中最小的一种,然后一直做到第一步,找最小值。

【AC_Code】

#include <iostream>
#include <algorithm>
#include <climits>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

const int N = 2e3 + 10; int a[N][N], ans = INT_MAX;

void solve()
{
	int n, m; cin >> n >> m;
	for (int i = 0; i < m; i ++) for (int j = 0; j < n; j ++) cin >> a[i][j];
	for (int j = n - 2; j >= 0; j --) for (int i = 0; i < m; i ++)
		a[i][j] += min(a[i][j + 1], a[(i + 1) % m][j + 1]);
	for (int i = 0; i < m; i ++) ans = min(a[i][0], ans);
	cout << ans << '\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

2. 【5.20】P1387 最大正方形

题目链接:https://www.luogu.com.cn/problem/P1387

【分析】

简单动态规划题,状态转移方程:f[i][j] = min(f[i - 1][j - 1], min(f[i - 1][j], f[i][j - 1])) + 1。

  • f[i][j]代表正方形右下角坐标为i,j所构成的最大正方形边长。
  • 注意下标从1开始比较方便,从0开始会导致非法访问,需考虑边界情况。

【AC_Code】

#include <iostream>
#include <algorithm>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

int a[105][105], f[105][105], ans;

void solve()
{
	int n, m; cin >> n >> m;
	for (int i = 1; i <= n; i ++) for (int j = 1; j <= m; j ++)
	{
		cin >> a[i][j];
		if (a[i][j] == 1) f[i][j] = min(f[i - 1][j - 1], min(f[i - 1][j], f[i][j - 1])) + 1;
		ans = max(f[i][j], ans);
	}
	cout << ans << '\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

3. 【5.21】P1507 NASA的食物计划

题目链接:https://www.luogu.com.cn/problem/P1507

【分析】
01背包问题。

【AC_Code】

#include <iostream>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

const int N = 55; int H[N], T[N], K[N], f[501][501];

void solve()
{
	int h, t, n; cin >> h >> t >> n;
	for (int l = 0; l < n; l ++) cin >> H[l] >> T[l] >> K[l];
	for (int l = 0; l < n; l ++)
	for (int i = h; i >= H[l]; i --) for (int j = t; j >= T[l]; j --)
	{
		f[i][j] = max(f[i][j], f[i - H[l]][j - T[l]] + K[l]);
	}
	cout << f[h][t] << '\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

4. 【5.22】P1616 疯狂的采药

题目链接:https://www.luogu.com.cn/problem/P1616

【分析】
完全背包问题。

【AC_Code】

#include <iostream>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
using ll = long long;

const int N = 1e4 + 10, M = 1e7 + 10; ll a[N], b[N], f[M];

void solve()
{
	int t, m; cin >> t >> m;
	for (int i = 1; i <= m; i ++)
	{
		cin >> a[i] >> b[i];
		for (int j = a[i]; j <= t; j ++)
			f[j] = max(f[j], f[j - a[i]] + b[i]);
	}
	cout << f[t] << '\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

5.【5.23】P1679 神奇的四次方数

题目链接:https://www.luogu.com.cn/problem/P1679

【分析】
可以dfs+剪枝,也可以dp。

【AC_Code1 | 动态规划】

#include <iostream>
#include <algorithm>
#include <cmath>
#include <climits>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

const int N = 1e5 + 10; int a[N], f[N];

void solve()
{
	int m; cin >> m; for (int i = 1; i <= m; i ++) f[i] = INT_MAX;
	for (int i = 1; i <= sqrt(sqrt(m)); i ++) a[i] = pow(i, 4);
	for (int i = 1; i <= sqrt(sqrt(m)); i ++) for (int j= a[i]; j <= m;j ++)
	{
		f[j] = min(f[j], f[j - a[i]] + 1);
	}
	cout << f[m] <<'\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

【AC_Code2 | 搜索】

#include <iostream>
#include <cmath>
#include <climits>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

int n, ans = INT_MAX;

void dfs(int sum, int cnt, int last)
{
	if (sum > n || cnt > ans) return ;
	if (sum == n) { ans = cnt; return ; }
	for (int i = sqrt(sqrt(n)) + 1; i >= last; i --) dfs(sum + i * i * i * i, cnt + 1, i);
}

void solve() { cin >> n; dfs(0, 0, 1); cout << ans << '\n'; }

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

6. 【5.24】P1049 [NOIP 2001 普及组] 装箱问题

题目链接:https://www.luogu.com.cn/problem/P1049

【分析】
01背包。

【AC_Code】

#include <iostream>
#include <algorithm>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

const int N = 40, M = 2e4 + 10; int v[N], f[M];

void solve()
{
	int V, n; cin >> V >> n;
	for (int i = 1; i <= n; i ++)
	{
		cin >> v[i];
		for (int j = V; j >= v[i]; j --)
    		f[j] = max(f[j], f[j - v[i]] + v[i]);
	}
	cout << V - f[V] << '\n';
}

int main()
{
    IOS int _ = 1;   // cin >> _;
    while (_ --) solve();
    
    return 0;
}

7. 【5.25】P1044 [NOIP 2003 普及组] 栈

题目链接:https://www.luogu.com.cn/problem/P1044

【分析】

  • f[20]存储卡特兰数,初始值为f[0]=1、f[1]=1、f[2]=2。
  • 利用公式f[i] += f[j-1] × f[i-j]枚举最后出栈元素位置,组合左右子问题解。
  • 计算1~n通过栈操作的合法输出序列数,本质是卡特兰数的应用。

【AC_Code】

#include <iostream>
#define IOS ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;

int f[20] = { 1, 1, 2 };

void solve()
{
	int n; cin >> n;
	for (int i = 3; i <= n; i ++) for (int j = 1; j <= i; j ++) f[i] += f[j - 1] * f[i - j];
	cout << f[n] << '\n';
}

int main()
{
	IOS int _ = 1;   // cin >> _;
	while (_ --) solve(); 
	
	return 0;
}

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Guiat

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

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

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

打赏作者

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

抵扣说明:

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

余额充值