【每日一题 | 2025年5.19 ~ 5.25】动态规划相关题
个人主页:Guiat
归属专栏:每日一题
文章目录
- 1. 【5.19】P1130 红牌
- 2. 【5.20】P1387 最大正方形
- 3. 【5.21】P1507 NASA的食物计划
- 4. 【5.22】P1616 疯狂的采药
- 5.【5.23】P1679 神奇的四次方数
- 6. 【5.24】P1049 [NOIP 2001 普及组] 装箱问题
- 7. 【5.25】P1044 [NOIP 2003 普及组] 栈
正文
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;
}
结语
感谢您的阅读!期待您的一键三连!欢迎指正!