南大算法设计与分析课程OJ答案代码(2)最大子序列和问题、所有的逆序对
问题 A: 最大子序列和问题
时间限制: 1 Sec 内存限制: 4 MB提交: 184 解决: 66
提交 状态 算法问答
题目描述
给定一整数序列 a1, a2, …, an,求 a1~an 的一个子序列 ai~aj,使得从 ai 到 aj 的和最大。
只需要求出最大子序列的和,而不需要求出最大的那个序列。
输入
一组整数,数字和数字之间以空格隔开。
输出
该整数序列中最大子序列的和
样例输入-2 11 -4 13 -5 -2
|
样例输出20
|
提示
应用穷举法可以得到 O(n3) 的算法,优化它即可得到 O(n2) 的算法。这两个算法将会超时。
利用分治的思想可以有 O(n*logn) 的算法。
也有聪明的算法,它的复杂度是 O(n) 的。
另请注意:输入多少个数是未知的。请思考如何处理。
利用分治的思想可以有 O(n*logn) 的算法。
也有聪明的算法,它的复杂度是 O(n) 的。
另请注意:输入多少个数是未知的。请思考如何处理。
答案看这里
问题 B: 所有的逆序对
时间限制: 2 Sec 内存限制: 5 MB提交: 289 解决: 49
提交 状态 算法问答
题目描述
给出一个字符串数组,如果(按照字典序)一个大的字符串在比它小的字符串前面我们称这两个字符串组成一个“逆序对”。你需要找到所有的逆序对的个数。
输入
第一行是数组大小,第二行是以空格分隔的字符串数组.
注:预先知道每个字符串的长度都是 10.
输出
所有的逆序对个数. 这次需要大家先输出一个字符串,它是“我已阅读关于抄袭的说明”的汉语拼音.输出此行的提交我们将认为已经完全阅读并了解了“关于抄袭的说明”公告.
注意:结果比较大,请用 long 类型保存.
样例输入3
aaaaaaaaaa cccccccccc bbbbbbbbbb
|
样例输出wo yi yue du guan yu chao xi de shuo ming
1
|
提示
不要使用蛮力算法
答案
暴力解法,会超时
long long a(vector<string>& v, int pos1, int pos2) { long long w = 0; for (int i = pos1; i <= pos2; ++i) { for (int j = i + 1; j <= pos2; ++j) { if (v[i] > v[j]) ++w; } } return w; }
归并排序的思想,只需要在归并排序的基础之上加上一个统计量,和一行代码,但是下面的做法会超出内存限制
void merge(vector<string>& v, int pos1, int mid, int pos2, long long& nums) { //从0开始的数组,如果两个位置分别为p1和p2,其中p1<p2,则p1到p2距离的元素有p2-p1+1个 vector<string> n1 (v.begin()+pos1,v.begin()+mid+1); vector<string> n2 (v.begin()+mid+1,v.begin()+pos2+1); n1.emplace_back("zzzzzzzzzzzzzzzzzzzz"); n2.emplace_back("zzzzzzzzzzzzzzzzzzzz"); int n1_pos = 0; int n2_pos = 0; for (int i = pos1; i <= pos2;++i) { if (n1[n1_pos] <= n2[n2_pos]) { v[i] = n1[n1_pos]; ++n1_pos; }else{ //在这加上统计量 nums += n1.size() - n1_pos-1; v[i] = n2[n2_pos]; ++n2_pos; } } } void mergesort(vector<string>& v, int pos1, int pos2, long long& nums) { if (pos1 < pos2) { int mid = (pos1 + pos2) / 2; mergesort(v,pos1,mid,nums); mergesort(v,mid+1,pos2,nums); merge(v,pos1,mid,pos2,nums); } } //这是测试用例 int main() { int nums = 0; cin >> nums; string temp; vector<string> v(nums,""); for (int i = 0; i < nums; ++i) { cin >> temp; v[i] = temp; } vector<string> v = { "aaaaaaaaaa", "cccccccccc", "bbbbbbbbbb" }; long long result = 0; mergesort(v, 0, v.size() - 1, result); cout << "wo yi yue du guan yu chao xi de shuo ming" << endl; cout << result << endl; //system("pause"); return 0; }
经大佬提醒,不在递归时分配vector,而是在开始递归之前申请一个help的vector用来帮助归并排序,这样可以减小内存使用,但是上面使用哨兵的方法就不能用了,代码稍微复杂了一些,但任然是归并排序加上一行统计代码。
void merge(vector<string>& v, int pos1, int mid, int pos2, long long& nums, vector<string>& help) { //从0开始的数组,如果两个位置分别为p1和p2,其中p1<p2,则p1到p2距离的元素有p2-p1+1个 for (int i = pos1; i <= pos2; ++i) help[i] = v[i]; int n1_pos = pos1; int n2_pos = mid+1; for (int i = pos1; i <= pos2;++i) { //当一个数组已经遍历完成时 if (n1_pos == mid + 1) { while (n2_pos != pos2 + 1) { v[i++] = help[n2_pos++]; } break; } if (n2_pos == pos2 + 1) { while (n1_pos != mid + 1) { v[i++] = help[n1_pos++]; } break; } //其他情况 if (help[n1_pos] <= help[n2_pos]) { v[i] = help[n1_pos]; ++n1_pos; }else{ //在这加上统计量 nums += mid-n1_pos+1; v[i] = help[n2_pos]; ++n2_pos; } } } void mergesort(vector<string>& v, int pos1, int pos2, long long& nums,vector<string>& help) { if (pos1 < pos2) { int mid = (pos1 + pos2) / 2; mergesort(v,pos1,mid,nums,help); mergesort(v,mid+1,pos2,nums,help); merge(v,pos1,mid,pos2,nums,help); } } //这是测试用例 int main() { int nums = 0; cin >> nums; string temp; vector<string> v(nums,""); for (int i = 0; i < nums; ++i) { cin >> temp; v[i] = temp; } //vector<string> v = { "4","3","2","1" }; vector<string> help(v.size()," "); long long result = 0; mergesort(v, 0, v.size() - 1, result,help); cout << "wo yi yue du guan yu chao xi de shuo ming" << endl; cout << result << endl; system("pause"); return 0; }