P1048 [NOIP 2005 普及组] 采药
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 222 个整数 TTT(1≤T≤10001 \le T \le 10001≤T≤1000)和 MMM(1≤M≤1001 \le M \le 1001≤M≤100),用一个空格隔开,TTT 代表总共能够用来采药的时间,MMM 代表山洞里的草药的数目。
接下来的 MMM 行每行包括两个在 111 到 100100100 之间(包括 111 和 100100100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
输入 #1
70 3
71 100
69 1
1 2
输出 #1
3
一道经典01背包,主要还是列状态转移方程,这道题状态转移方程大致为
如果时间足够
dp[i][j]=max(dp[i−1][j],dp[i−1][j−time[i]]+price[i])dp[i][j] = max(dp[i-1][j], dp[i-1][j-time[i]] + price[i])dp[i][j]=max(dp[i−1][j],dp[i−1][j−time[i]]+price[i])
时间不够
dp[i][j]=dp[i−1][j]dp[i][j] = dp[i-1][j]dp[i][j]=dp[i−1][j]
#include<bits/stdc++.h>
using namespace std;
int a[1002], b[1002], dp[1002][1002];
int main()
{
int T, m;
cin >> T >> m;
for (int i = 1; i <= m; i++)
cin >> a[i] >> b[i];
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= T; j++)
{
if (j >= a[i]) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + b[i]);
}
else
dp[i][j] = dp[i - 1][j];
}
}
cout << dp[m][T];
return 0;
}
P2196 [NOIP 1996 提高组] 挖地雷
题目描述
在一个地图上有 N (N≤20)N\ (N \le 20)N (N≤20) 个地窖,每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径。当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使某人能挖到最多的地雷。
输入格式
有若干行。
第 111 行只有一个数字,表示地窖的个数 NNN。
第 222 行有 NNN 个数,分别表示每个地窖中的地雷个数。
第 333 行至第 N+1N+1N+1 行表示地窖之间的连接情况:
第 333 行有 n−1n-1n−1 个数(000 或 111),表示第一个地窖至第 222 个、第 333 个 …\dots… 第 nnn 个地窖有否路径连接。如第 333 行为 11000⋯011000\cdots 011000⋯0,则表示第 111 个地窖至第 222 个地窖有路径,至第 333 个地窖有路径,至第 444 个地窖、第 555 个 …\dots… 第 nnn 个地窖没有路径。
第 444 行有 n−2n-2n−2 个数,表示第二个地窖至第 333 个、第 444 个 …\dots… 第 nnn 个地窖有否路径连接。
……
第 n+1n+1n+1 行有 111 个数,表示第 n−1n-1n−1 个地窖至第 nnn 个地窖有否路径连接。(为 000 表示没有路径,为 111 表示有路径)。
输出格式
第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。
第二行只有一个数,表示能挖到的最多地雷数。
输入输出样例 #1
输入 #1
5
10 8 4 7 6
1 1 1 0
0 0 0
1 1
1
输出 #1
1 3 4 5
27
太弱了做了好久,dp太差了
看题解这道题可以dfs爆搜
主要是列状态转移以及怎么存路径,由于数据太弱了所以全存也不会超时
代码如下
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int N;
int a[22];
int b[22][22];
int dp[22];
queue<int> dpq[22];
int main() {
cin >> N;
for (int i = 0; i < N; i++)cin >> a[i], dp[i] = a[i], dpq[i].push(i + 1);
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N - i - 1; j++) {
cin >> b[i][j];
}
}
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N - 1 - i; j++) {
if (b[i][j]) {
if (dp[i + j + 1] < dp[i] + a[i + j + 1]) {
dpq[i + j + 1] = dpq[i];//路径优化
dpq[i + j + 1].push(i + j + 2);//存路径
}
dp[i + j + 1] = max(dp[i + j + 1], dp[i] + a[i + j + 1]);//状态转移方程
}
}
}
int maxx = 0;
int k;
for (int i = 0; i < N; i++) {
if (dp[i] > maxx)k = i;
maxx = max(dp[i], maxx);
}
while (!dpq[k].empty()) {
cout << dpq[k].front() << ' ';
dpq[k].pop();
}
cout << endl;
cout << maxx;
return 0;
}
P4017 最大食物链计数
题目背景
你知道食物链吗?Delia 生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条。于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧。
题目描述
给你一个食物网,你要求出这个食物网中最大食物链的数量。
(这里的“最大食物链”,指的是生物学意义上的食物链,即最左端是不会捕食其他生物的生产者,最右端是不会被其他生物捕食的消费者。)
Delia 非常急,所以你只有 111 秒的时间。
由于这个结果可能过大,你只需要输出总数模上 801120028011200280112002 的结果。
输入格式
第一行,两个正整数 n、mn、mn、m,表示生物种类 nnn 和吃与被吃的关系数 mmm。
接下来 mmm 行,每行两个正整数,表示被吃的生物A和吃A的生物B。
输出格式
一行一个整数,为最大食物链数量模上 801120028011200280112002 的结果。
输入输出样例 #1
输入 #1
5 7
1 2
1 3
2 3
3 5
2 5
4 5
3 4
输出 #1
5
一开始以为是最长食物链的长度,我说怎么这么简单
结果是个拓扑的题,从来没做过最后看了题解才写出来
大概意思就是从入度为 000 的点到出度为 000 的点的路径总和可以用拓扑的方法写
这里面 111 就是入度为 000 的点,先定义入度为 000 的点的路径总和为 111
那么 111 能到的点路径总和就加上 111 的路径总和的值
就是 d[i]+=d[k]d[i] += d[k]d[i]+=d[k]
接着把 111 弹出队列, 继续查入度为 000 的节点,代码如下
#include<bits/stdc++.h>
using namespace std;
#define long long
int n, m;
int num = 0;
int b[5005][5005];
int ru[5005];
int chu[5005];
int f[5005];
queue<int> q;
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x,y;
cin >> x >> y;
b[x][y] = 1;
chu[x]++;
ru[y]++;
}
for (int i = 1; i <= n; i++) {
if (ru[i] == 0) {
q.push(i);
f[i] = 1;
}
}
while (!q.empty()) {
int k = q.front();
q.pop();
for (int i = 1; i <= n; i++) {
if (!b[k][i])continue;
f[i] += f[k];
f[i] %= 80112002;
ru[i]--;
if (ru[i] == 0) {
if (chu[i] == 0) {
num += f[i];
num %= 80112002;
}
q.push(i);
}
}
}
cout << num;
return 0;
}
P1115 最大子段和
题目描述
给出一个长度为 nnn 的序列 aaa,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度 nnn。
第二行有 nnn 个整数,第 iii 个整数表示序列的第 iii 个数字 aia_iai。
输出格式
输出一行一个整数表示答案。
输入输出样例 #1
输入 #1
7
2 -4 3 -1 2 -4 3
输出 #1
4
说明/提示
样例 1 解释
选取 [3,5][3, 5][3,5] 子段 {3,−1,2}\{3, -1, 2\}{3,−1,2},其和为 444。
数据规模与约定
- 对于 40%40\%40% 的数据,保证 n≤2×103n \leq 2 \times 10^3n≤2×103。
- 对于 100%100\%100% 的数据,保证 1≤n≤2×1051 \leq n \leq 2 \times 10^51≤n≤2×105,−104≤ai≤104-10^4 \leq a_i \leq 10^4−104≤ai≤104。
做的最快的一集
话不多说直接贴代码,前缀和的题
数据是坑点,$ a_i $ 的最小值是 −104-10^4−104
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200005];
int b[200005];
int main() {
cin >> n;
int maxx = -1e9;//数据中最小值不是0是-1e4
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i];
if (b[i - 1] > 0)b[i] += b[i - 1];
maxx = max(maxx, b[i]);
}
cout << maxx;
return 0;
}
4万+

被折叠的 条评论
为什么被折叠?



