PTA 1007
1007(最大连续子序列和、动态规划dp)
Given a sequence of K integers { N1, N2, …, NK }. A continuous subsequence is defined to be { Ni, Ni+1, …, Nj } where 1 <= i <= j <= K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.
Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (<= 10000). The second line contains K numbers, separated by a space.
Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.
Sample Input:
10
-10 1 2 3 4 -5 -23 3 7 -21
Sample Output:
10 1 4
题目大意: 给你一个长度为k的整数序列,输出最大连续子序列和,最大连续子序列的第一项和最后一项,则定义最大和为0,输出这个整数序列的第一项和最后一项
思路:满足最优子结构,用动态规划可以解决
算法步骤:
-
拆分问题成包含子问题的结构:前k个元素最大连续子序列和,可以拆分成前k-1个元素的最大连续子序列和与a[k]之间的联系
-
推导状态转移方程:
当a[k] <= 0 时,dp[k] == dp[k-1];
当a[k] > 0 时,dp[k] = max(dp[k-1], sum + a[i]); sum是临时最大和,即是以a[k-1]为右边界的最大连续子序列和,若sum < 0, 则令 sum = 0. ,是一个临时累积变量,核心作用是实时计算 “当前正在考察的连续子数组的和”。
-
初始化边界条件
-
计算 DP 表(或记忆化缓存)
-
xxxxxxxxxx59 1#include<bits/stdc++.h>2using namespace std;3const int INF = 0x3f3f3f3f;4int n, m, c1, c2;5int teamcount[505]; // 各站点队伍的数量6int e[505][505] ; //点与点之间的距离7int w[505], num[505], dis[505];8bool visited[505];910int main() {11 cin >> n >> m >> c1 >> c2;12 fill(dis, dis + 505, INF);13 fill(e[0], e[0] + 505 * 505, INF);1415 for(int i = 0; i < n; i++) {16 cin >> teamcount[i];17 }18 int a, b, c;19 for(int i = 0; i < m; i++) {20 cin >> a >> b >> c;21 e[a][b] = e[b][a] = c;22 }2324 w[c1] = teamcount[c1];25 dis[c1] = 0;26 num[c1] = 1;2728 for(int i = 0; i < n; i++) {29 int minn = INF, u = -1;30 for(int j = 0; j < n; j++) {31 if(!visited[j] && dis[j] < minn) {32 u = j;33 minn = dis[j];34 }35 }36// 找完了37 if(u == -1) break;38 visited[u] = true;39 for(int k = 0; k < n; k++) {40 if(!visited[k] && e[u][k] != INF) {41 if(e[u][k] + dis[u] < dis[k]) {42 dis[k] = e[u][k] + dis[u];43 w[k] = w[u] + teamcount[k];44 num[k] = num[u];45 } else if(e[u][k] + dis[u] == dis[k]) {46 if(w[u] + teamcount[k] > w[k]){47 w[k] = w[u] + teamcount[k]; 48 }49 num[k] += num[u];50 }5152 }53 }5455 }56 57 cout << num[c2] << " " << w[c2];5859}c++
但这时运行时,就发现有一个案例错误:
//input:2 -1 0 output:0 0 0
运行代码会输出: 0 -1 0
这是为什么呢?
因为我把x , y 初始化成了int x = 0, y = k - 1; 但是 在运行代码时,始终 sum > dp[i - 1] 都没有达到这个条件,导致我的x, y 一直没有更新,导致错误。
#include<bits/stdc++.h>
using namespace std;
int k;
int a[10005], dp[10005];
bool isneg = true;
// 如果也计算负数怎么办
int main() {
cin >> k;
int sum;
for(int i = 0; i < k; i++) {
cin >> a[i];
if(a[i] >= 0) isneg = false;
}
sum = 0;
int x = 0, y = k - 1;
int tempindex = 0;
for(int i = 0; i < k; i++) {
sum += a[i];
if(sum < 0) {
sum = 0;
tempindex = i + 1;
}
if(a[i] <= 0) dp[i] = dp[i - 1];
else{
if(dp[i - 1] < sum) {
x = tempindex;
dp[i] = sum;
y = i;
} else{
dp[i] = dp[i - 1];
}
}
}
if(isneg) cout << 0 << " " << a[0] << " " << a[k-1];
else cout << dp[k-1] << " " << a[x] << " " << a[y];
return 0;
}
那怎么解决呢?
最简单的方式就是针对这个案例添加一个判断条件即可
#include<bits/stdc++.h>
using namespace std;
int k;
int a[10005], dp[10005];
bool isneg = true;
// 如果也计算负数怎么办
int main() {
cin >> k;
int sum;
for(int i = 0; i < k; i++) {
cin >> a[i];
if(a[i] >= 0) isneg = false;
}
sum = 0;
int x = 0, y = k - 1;
int tempindex = 0;
for(int i = 0; i < k; i++) {
sum += a[i];
if(sum < 0) {
sum = 0;
tempindex = i + 1;
}
if(a[i] < 0) dp[i] = dp[i - 1];
else {
if(sum > dp[i - 1]) {
x = tempindex;
dp[i] = sum;
y = i;
} else if(sum == dp[i - 1] && sum ==0) {
x = tempindex;
dp[i] = sum;
y = i;
} else {
dp[i] = dp[i-1];
}
}
}
if(isneg) cout << 0 << " " << a[0] << " " << a[k-1];
else cout << dp[k-1] << " " << a[x] << " " << a[y];
return 0;
}
如果else if(sum == dp[i - 1] && sum ==0)换成 else if(sum == dp[i - 1] && sum ==0)会发生错误
错误案例:
5
-1 1 2 3 0
它会导致y在最后等于0 ,更新;导致 y = 4; 输出:6 1 0
实现应该输出 6 1 3
其实这已经解决了,但我看了柳chuo大神的代码,发现了自己代码中的很多不足
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<int> v(n);
int leftindex = 0, rightindex = n - 1, sum = -1, temp = 0, tempindex = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &v[i]);
temp = temp + v[i];
if (temp < 0) {
temp = 0;
tempindex = i + 1;
} else if (temp > sum) {
sum = temp;
leftindex = tempindex;
rightindex = i;
}
}
if (sum < 0) sum = 0;
printf("%d %d %d", sum, v[leftindex], v[rightindex]);
return 0;
}
-
实际上只是得到最终的结果,只是一维的动态规划,可以不用dp数组记录,只用一个变量sum来记录当前最大的连续子序列和即可
用dp数组的话
-
用dp数组的话,在sum <= dp[i-1],还要更新dp[i] = dp[i-1]
-
如果出现-1,3,0类似的话,需要更新x 和 y,需要特殊处理,增加了很多考虑
-
不用的话,就不用考虑
675

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



