写在前面:只是通过了平台oj,用例较少,不保证正确。
第一次作业
汉诺塔
#include <iostream>
using namespace std;
void moveDisks(int n, char fromTower, char toTower, char auxTower){
if(n == 1){
cout << fromTower << '-' << toTower << endl;
} else{
moveDisks(n - 1, fromTower, auxTower, toTower);
moveDisks(1, fromTower, toTower, auxTower);
moveDisks(n - 1, auxTower, toTower, fromTower);
}
return;
}
int main(){
//3个柱子ABC n个盘子 可以不断输入和输出
int n;
while (cin >> n){
moveDisks(n, 'A', 'C', 'B');
}
return 0;
}
一只小蜜蜂
#include <iostream>
using namespace std;
int f(int a, int b){
if(b - a == 1){
return 1;
}else if(b - a == 2){
return 2;
}else{
return f(a, b - 1) + f(a, b - 2);
}
}
int main(){
//3个柱子ABC n个盘子 可以不断输入和输出
int n, a, b;
cin >> n;
while (n--){
cin >> a >> b;
cout << f(a, b) << endl;
}
return 0;
}
Digital Roots
#include <iostream>
#include <cstring>
using namespace std;
int f(string n){
if(n.size() == 1)return atoi(n.c_str());
else{
while (n.size() > 1){
int temp = 0;
for(int i = 0; i < n.size(); i++){
temp += n[i] - '0';
}
n = to_string(temp);
}
return atoi(n.c_str());
}
}
int main(){
string n;
cin >> n;
while (n != "0"){
cout << f(n) << endl;
cin >> n;
}
return 0;
}
Sum of Numbers
#include <iostream>
using namespace std;
int main(){
double m = 0;
int n = 0;
double pos = 0, neg = 0;
while (n != 10){
cin >> m;
if(m > 0) pos += m;
else if(m < 0) neg += m;
n++;
}
printf("%.2f,%.2f,%.2f", pos, neg, pos + neg);
return 0;
}
Fighting strength vs equipment逆序对个数
归并排序的过程中得到逆序对个数
#include <iostream>
using namespace std;
long long int a[1000001], temp[1000001];//用全局变量传参时简单很多
long long int tot = 0;//逆序对个数
void f(int m, int n){
if(m == n)return;
long long int mid = (m + n) / 2;
f(m, mid);
f(mid + 1, n);//对左右进行归并排序,使均为升序
long long int i = m;//从左边的第一个元素开始
long long int j = mid + 1;//从右边的第一个元素开始
long long int now = m;//temp现在的指针
while (i <= mid && j <= n){
if(a[i] <= a[j]){
temp[now++] = a[i++];
} else{
tot += mid + 1 - i;//注意不是j - i!!!
temp[now++] = a[j++];
}
}
while (i <= mid){
temp[now++] = a[i++];
}
while (j <= n){
temp[now++] = a[j++];
}
for(i = m; i <= n; i++){
a[i] = temp[i];
}
}
int main(){//归并排序的过程中求逆序对
long long int n = 0;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
f(1, n);//因为这里不是全局变量,所以要传参
cout << tot;
return 0;
}
判断回文数
#include <iostream>
#include <cstring>
using namespace std;
int f(string n){
for(int i = 0; i < n.size() / 2; i++){
if(n[i] != n[n.size() - 1 - i])return 0;
}
return 1;
}
int main(){//归并排序的过程中求逆序对
string n;
cin >> n;
cout << f(n);
return 0;
}
第二次作业
h指数
#include <iostream>
using namespace std;
int a[10005];//用全局变量传参时简单很多
void fixHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root + 1; i < heapSize; i = i * 2 + 1){
if(i + 1 < heapSize && a[i] < a[i + 1]){//若右节点比左节点大,指向右节点
i++;
}
if(a[i] > temp){//如果子节点大于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void heapSort(int a[], int n){
//1、构建最大堆
int heapLen = n;
for(int i = heapLen / 2 - 1; i >= 0; i--){
fixHeap(a, i, heapLen);
}
//2、调整堆结构
for (int i = heapLen - 1; i > 0; i--){
//交换最大值和最后一个数
int temp = a[i];//最后一个数
a[i] = a[0];
a[0] = temp;
fixHeap(a,0,i);//排好序的就不用管了,heapSize会缩小
//注意以0开始,所以heapSize是i+1
}
return;
}
int main(){
int i = 0;
while(cin >> a[i]){
i++;
}
heapSort(a, i);//从小到大排列
for(int j = 0; j < i; j++){
if(a[j] >= i - j){//找到第一个论文引用次数大于后续论文的数量
cout << i - j << endl;
break;
}
}
return 0;
}
最大硬币数
#include <iostream>
#include <algorithm>
using namespace std;
long long int a[10005];//用全局变量传参时简单很多
//3n堆硬币 piles[]返回能获得的最大硬币数 位于中间的数和最大
//1 2 2 4 7 8 取1 7 8 2 2 4 最大的两个+最小的一个
int main(){//归并排序的过程中求逆序对
int i = 0;
while (cin >> a[i++]);//未知长度的数组读入
sort(a, a + i, greater<int>());//从大到小排序
int max = 0;
for(int j = 0; j < i / 3; j++){
max += a[2 * j + 1];
}
cout << max << endl;
return 0;
}
n皇后
#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;//记录解的数量
int col[10005];//记录各皇后所在的行列
//别忘了反对角线!!!!
bool find(int k, int i){//k是行号 i是列号
for(int j = 1; j < k; j++){//看1~k-1行 有没有 和 (k,i)同列的(j,i)或者同对角线的(j,col[j])
if(col[j] == i || abs(i - col[j]) == abs(k - j)){
return false;
}
}
return true;
}
//这里利用回溯
void place(int k, int n){
for(int i = 1; i <= n; i++){//第k行的第一列到第n列
if(find(k, i)){
col[k] = i;
if(k == n){
ans++;
}
else place(k + 1, n);
}
}
};
int main(){
int n = 0;
cin >> n;
place(1, n);
cout << ans << endl;
return 0;
}
最大间距
#include <iostream>
#include <algorithm>
using namespace std;
int a[10005];//记录各皇后所在的行列
int main(){
int i = 0;
while(cin >> a[i]){
i++;
}
if(i == 1){
cout << 0 << endl;
} else{
sort(a, a + i);
int max = -1;
for(int j = 0; j < i - 1; j++){
if((a[j + 1] - a[j]) > max){
max = a[j + 1] - a[j];
}
}
cout << max << endl;
}
return 0;
}
最大子数组
#include <iostream>
using namespace std;
int a[10005];//记录各皇后所在的行列
int Max3(int sum, int sum1, int i);
int MaxSubSum(int a[], int left, int right){
// 这个条件要加上,否则不好退出
if(left == right){
return a[left];
}
int center = (left + right) / 2;
int MaxLeftSum = MaxSubSum(a, left, center);
int MaxRightSum = MaxSubSum(a, center + 1, right);
int MaxLeftBorderSum = 0, LeftBorderSum = 0;
for(int i = center; i >= left; i--){
LeftBorderSum += a[i];
if(LeftBorderSum > MaxLeftBorderSum){
MaxLeftBorderSum = LeftBorderSum;
}
}
int MaxRightBorderSum = 0, RightBorderSum = 0;
for(int i = center + 1; i <= right; i++){
RightBorderSum += a[i];
if(RightBorderSum > MaxRightBorderSum){
MaxRightBorderSum = RightBorderSum;
}
}
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
int Max3(int i, int j, int k) {
int e,f; /*这里需要进行两次的比较,要用到两个变量*/
e= i > j? i : j; /*这里比较x和y的大小,并将大的值赋给e*/
f= e > k? e : k; /*将x、y中大的值e,继续和z进行比较*/
return f; /*返回给函数调用的地方*/
}
int main(){
int i = 0;
while(cin >> a[i]){
i++;
}
cout << MaxSubSum(a, 0, i) << endl;
return 0;
}
桶排序
#include <iostream>
#include <queue>
#include <string>
using namespace std;
int a[10005];
int temp[10005];
void fixHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root + 1; i < heapSize; i = i * 2 + 1){
if(i + 1 < heapSize && a[i] < a[i + 1]){//若右节点比左节点大,指向右节点
i++;
}
if(a[i] > temp){//如果子节点大于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void heapSort(int a[], int n){
//1、构建最大堆
int heapLen = n;
for(int i = heapLen / 2 - 1; i >= 0; i--){
fixHeap(a, i, heapLen);
}
//2、调整堆结构
for (int i = heapLen - 1; i > 0; i--){
//交换最大值和最后一个数
int temp = a[i];//最后一个数
a[i] = a[0];
a[0] = temp;
fixHeap(a,0,i);//排好序的就不用管了,heapSize会缩小
//注意以0开始,所以heapSize是i+1
}
return;
}
int main(){
int i = 0;
int max = -1;
int min = INT32_MAX;
while(cin >> a[i] && a[i] != -1){
if(a[i] > max) max = a[i];
if(a[i] < min) min = a[i];
i++;
}
queue<int> bucket[i];
int len = (max - min) / i + 1;
for(int j = 0; j < i; j++){//放入n个桶中
bucket[(a[j] - min) / len].push(a[j]);
}
int now = 0;
for(int j = 0; j < i; j++){
if(bucket[j].size() == 0) continue;
if(bucket[j].size() == 1){
cout << bucket[j].front() << " ";
continue;
}
while(!bucket[j].empty()){
temp[now++] = bucket[j].front();
bucket[j].pop();
}
heapSort(temp, now);
for(int k = 0; k < now; k++){
cout << temp[k] << " ";
temp[k] = 0;
}
now = 0;
}
return 0;
}
计数排序
#include <iostream>
#include <vector>
using namespace std;
int a[10005];
int main(){
int i = 0;
int max = -1;
int min = INT32_MAX;
while(cin >> a[i] && a[i] != -1){
if(a[i] > max) max = a[i];
if(a[i] < min) min = a[i];
i++;
}
vector<int> count(max - min + 1,0);
for(int j = 0; j < i; j++){
count[a[j] - min]++;
}
for(int j = 0; j < max - min + 1; j++){
while(count[j] > 0 && j + min >= 0){//通过count下标来推出该输出的值
cout << j + min << " ";
count[j]--;
}
}
return 0;
}
堆排序
#include <iostream>
using namespace std;
int a[10005];
void fixHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root + 1; i < heapSize; i = i * 2 + 1){
if(i + 1 < heapSize && a[i] < a[i + 1]){//若右节点比左节点大,指向右节点
i++;
}
if(a[i] > temp){//如果子节点大于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void heapSort(int a[], int n){
//1、构建最大堆
int heapLen = n;
for(int i = heapLen / 2 - 1; i >= 0; i--){
fixHeap(a, i, heapLen);
}
//2、调整堆结构
for (int i = heapLen - 1; i > 0; i--){
//交换最大值和最后一个数
int temp = a[i];//最后一个数
a[i] = a[0];
a[0] = temp;
fixHeap(a,0,i);//排好序的就不用管了,heapSize会缩小
//注意以0开始,所以heapSize是i+1
}
return;
}
int main(){
int i = 0;
while(cin >> a[i] && a[i] != -1){
i++;
}
heapSort(a, i);
for(int j = 0; j < i; j++){
cout << a[j] << " ";
}
return 0;
}
基数排序
#include <iostream>
#include <queue>
#include <string>
using namespace std;
int a[10005];
void radixSort(int a[], int len, int n){//len是数组长度 n是需要循环的次数(来源于最大数的长度)
queue<int> temp[10];
int cnt = 0;
int radix = 1;
while(cnt != n){
for(int i = 0; i < len; i++){
temp[(a[i] / radix) % 10].push(a[i]);
}
radix = radix * 10;
int now = 0;
for(int i = 0; i < 10; i++){
while(!temp[i].empty()){
a[now++] = temp[i].front();
temp[i].pop();
}
}
cnt++;
}
return;
}
int main(){
int i = 0;
int max = -1;
while(cin >> a[i] && a[i] != -1){
if(a[i] > max) max = a[i];
i++;
}
int n = to_string(max).size();
radixSort(a, i, n);
for(int j = 0; j < i; j++){
cout << a[j] << " ";
}
return 0;
}
希尔排序
#include <iostream>
#include <string>
using namespace std;
int a[10005];
//第一次写时的错误:注意shell不是两两比较!!!而是类似插入排序一起比较
void shellSort(int a[], int len){//len是数组长度
int tmp = 0;
for(int gap = len / 2; gap > 0; gap /= 2){
for(int i = gap; i < len; i++){
tmp = a[i];
int j = 0;
for(j = i; j >= gap && a[j - gap] > tmp; j -= gap){//数字不断往后挪空位
a[j] = a[j - gap];
}
a[j] = tmp;
}
}
// while(gap > 0){
// for(int i = 0; i + gap < len; i++){
// if(a[i] > a[i + gap]){
// temp = a[i];
// a[i] = a[i + gap];
// a[i + gap] = temp;
// }
// }
// gap /= 2;
// }
return;
}
int main(){
int i = 0;
while(cin >> a[i] && a[i] != -1){
i++;
}
shellSort(a, i);
for(int j = 0; j < i; j++){
cout << a[j] << " ";
}
return 0;
}
第三次作业
奇中位数
奇中位数
对顶堆:一个最大堆存小的数 一个最小堆存大的数
注意上滤(fixUp)下滤(fixHeap)的运用
#include <iostream>
using namespace std;
int a[10000005];
int q1[10000005];//小的数放这里 最大堆
int q2[10000005];//大的数放这里 最小堆
int num1 = 0;
int num2 = 0;
void fixMaxHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root; i <= heapSize; i = i * 2){
if(i + 1 <= heapSize && a[i] < a[i + 1]){//若右节点比左节点大,指向右节点
i++;
}
if(a[i] > temp){//如果子节点大于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void shiftUpMax(int q[], int key, int heapSize){//最大堆
int i = heapSize;
while(i >= 2 && q[i / 2] < key){
q[i] = q[i / 2];
i = i / 2;
}
q[i] = key;//把当前元素插入合适的地方
}
void fixMinHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root; i <= heapSize; i = i * 2){
if(i + 1 <= heapSize && a[i] > a[i + 1]){//若右节点比左节点小,指向右节点
i++;
}
if(a[i] < temp){//如果子节点小于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void shiftUpMin(int q[], int key, int heapSize){//最小堆
int i = heapSize;
while(i >= 2 && q[i / 2] > key){
q[i] = q[i / 2];
i = i / 2;
}
q[i] = key;//把当前元素插入合适的地方
}
int main(){
int n = 0;
int mid = 0;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
cin >> ws;
if(i == 1){
mid = a[1];
} else{
if(a[i] < mid){
shiftUpMax(q1, a[i], ++num1);
} else if(a[i] >= mid){
shiftUpMin(q2, a[i], ++num2);
}
}
if(i % 2 == 1){
if(num1 - num2 >= 2){
shiftUpMin(q2, mid, ++num2);
mid = q1[1];//新的中位数
q1[1] = q1[num1];
q1[num1--] = 0;
fixMaxHeap(q1, 1, num1);
} else if(num2 - num1 >= 2){
shiftUpMax(q1, mid, ++num1);
mid = q2[1];//新的中位数
q2[1] = q2[num2];
q2[num2--] = 0;
fixMinHeap(q2, 1, num2);
}
cout << mid << endl;
}
}
return 0;
}
原始线性选择
#include <iostream>
using namespace std;
double a[10000005];
int partition(double a[], int left, int right, int k){
if(left >= right){
return left;
}
double pivot = a[right - 1];
int i = left - 1;
for(int j = left; j < right; j++){
if(a[j] < pivot){
i++;
swap(a[i], a[j]);
}
}
swap(a[i + 1], a[right - 1]);
if(i + 1 - left == k){
return i + 1;
} else if(i + 1 - left < k){
partition(a, i + 2, right, k - (i + 1 - left) - 1);
} else{
partition(a, left, i + 1, k);
}
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int index = partition(a, 0, n, n / 2);
if(n % 2 == 1){
printf("%.6f", a[index]);
}else{
printf("%.6f", (a[index] + a[index - 1])/ 2);
}
}
#include <vector>
#include <algorithm>
#include <iostream>
#include <stdio.h>
using namespace std;
long long a[100000];
long long m, n;
long long ans = -1;
long long find(long long t) {//找到数组a中第一个大于等于t的元素的位置
long long l = 0, r = n - 1, ans = -1;
while (l <= r) {
long long min = (l + r) / 2;
if (a[min] >= t) {
ans = min;
r = min - 1;
}
else {
l = min + 1;
}
}
return ans;
}
bool check(long long val) {//返回true:中位数比val大 返回false:中位数比val小
long long count = 0;
for (long long i = 0; i < n - 1; i++) {
long long t = find(a[i] + val);
if (t != -1)
count += n - find(a[i] + val);
}
return count > m;
}
int main() {
while (scanf_s("%d", &n) != EOF) {
for (long long i = 0; i < n; i++) {
scanf_s("%d", &a[i]);
}
sort(a, a + n);
m = n * (n - 1) / 4;
long long l = 0, r = a[n - 1] - a[0];
while (l <= r) {
long long min = (l + r) / 2;
if (check(min)) {
l = min+1;
ans = min;
}
else {
r = min - 1;
}
}
cout << ans << endl;
}
}
线性选择算法
#include <iostream>
using namespace std;
int a[10000005];
int b[10000005];
int find5median(int a[], int left, int size);
int partition(int a[], int left, int right, int k, int pivot){
int i = left - 1;
for(int j = left; j < right; j++){
if(a[j] < pivot){
i++;
if(i != j)swap(a[i], a[j]);
} else if(a[j] == pivot){
if(j != right - 1){
if(a[right - 1] < pivot){
i++;
swap(a[j], a[right - 1]);
swap(a[i], a[j]);
} else{
swap(a[j], a[right - 1]);
}
}
}
}
swap(a[i + 1], a[right - 1]);
if(i + 1 - left == k){
return i + 1;
} else if(i + 1 - left < k){
if(right - i - 2 < 5){
partition(a, i + 2, right, k - (i + 1 - left) - 1, a[right - 1]);
} else{
partition(a, i + 2, right, k - (i + 1 - left) - 1, find5median(a, i + 2, right - i - 2));
}
} else{
if(i + 1 - left < 5){
partition(a, left, i + 1, k, a[i]);
}else{
partition(a, left, i + 1, k, find5median(a, left, i + 1 - left));
}
}
}
int find5median(int a[], int left, int size){//注意把这个找高效pivot提取出来,可以避免超时
int i, index;
for(i = 0; i < size / 5; i++){
index = partition(a, left + 5 * i, left + 5 * i + 5, 3, a[left + i + 4]);
b[i] = a[index];//存各组的中位数
}
index = partition(b, 0, i, i / 2, b[i - 1]);
int pivot = b[index];//得到整个数组的中位数
return pivot;
}
int findkth(int a[], int size, int k){
if(size < 5){
return partition(a, 0, size, k, a[size - 1]);
}else{
return partition(a, 0, size, k, find5median(a, 0, size));
}
}
int main(){
int n, k;
cin >> n;
cin >> k;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int index = findkth(a, n, k - 1);
cout << a[index] << endl;
}
第四次作业
等式方程
注意相等时一定要移动当前的根节点指向另一个结点,而不是移现有结点!!!
#include <iostream>
#include <vector>
using namespace std;
string op;
int root[30];//记录每个结点的根节点
vector<string> tmp;
int find_root(int i){
int j = i;
while(j != root[j]){
j = root[j];
}
return j;
}
int main(){
char a;
char b;
bool flag = true;
for(int i = 0; i < 30; i++){//记录每个字母的根节点
root[i] = i;
}
while(cin >> op){
a = op[0];
b = op[3];
if(op[1] == '='){//如果相等
root[find_root(b - 'a')] = find_root(a - 'a');
}else if(op[1] == '!'){//如果是不等
tmp.push_back(op);
}
}
for(int i = 0; i < tmp.size(); i++){
op = tmp[i];
a = op[0];
b = op[3];
if(find_root(a - 'a') == find_root(b - 'a')){
flag = false;
break;
}
}
if(flag){
cout << "true" << endl;
} else{
cout << "false" << endl;
}
}
朋友圈
注意当根节点需要变动时,总朋友圈数就会少1
#include <iostream>
using namespace std;
int ans;
int m[205][205];
int root[205];//记录每个结点的根节点
int find_root(int i){
while(i != root[i]){
i = root[i];
}
return i;
}
int main(){
int num;
int line = 0;
int col = 0;
char op;
while(cin >> num){
cin >> op;
if(op == ','){
m[line][col] = num;
col++;
} else if(op == ';'){
m[line][col] = num;
col = 0;
line++;
}else{
break;
}
}
for(int i = 0; i < col; i++){//初始化
root[i] = i;//先各自为组,组名也为自己的序号
}
ans = col;
for(int i = 0; i < col; i++){
for(int j = 0; j < col; j++){
if(j > i && m[i][j] == 1 && find_root(j) != find_root(i)){
root[j] = find_root(i);
ans--;
}
}
}
cout << ans << endl;
}
字母异位字符串分组
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
int ans;
map<string, int> tmp;
int main(){
string str;
string word;
cin >> str;
int left = -1;//存储字符串左边
for(int i = 0; i < str.length(); i++){
if(str[i] == '\"'){
if(left >= 0){
word = str.substr(left, i - left);
sort(word.begin(), word.end());
if(tmp.empty() || !tmp.count(word)){
tmp.insert(make_pair(word, 1));
} else{
tmp[word]++;
if(tmp[word] > ans){
ans = tmp[word];
}
}
left = -1;
} else{
left = i + 1;
}
}
}
cout << ans << endl;
}
前k个高频元素
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
map<int, int> mp;
int q[10005];//存放最小堆 注意下标从0开始
int N;//记录最小堆长度
void fixMinHeap(int a[], int root, int heapSize){
int temp = a[root];//先取出当前元素 9
for(int i = 2 * root; i <= heapSize; i = i * 2){
if(i + 1 <= heapSize && mp[a[i]] > mp[a[i + 1]]){//若右节点比左节点小,指向右节点
i++;
}
if(mp[a[i]] < mp[temp]){//如果子节点小于父节点,将子节点赋给父节点
a[root] = a[i];
root = i;//下移一层
} else{
break;
}
}
a[root] = temp;//把当前元素插入合适的地方
}
void shiftUpMin(int q[], int key, int heapSize){//最小堆
int i = heapSize;
while(i >= 2 && mp[q[i / 2]] > mp[key]){
q[i] = q[i / 2];
i = i / 2;
}
q[i] = key;//把当前元素插入合适的地方
}
bool cmp(int i, int j){
return mp[i] > mp[j];
}
//前k频出现的数:构造k大最小堆,然后不断与root比较
int main(){
int num;
char op;
int k;
while (cin >> num){
cin >> op;
if(mp.empty() || !mp.count(num)){
mp.insert(make_pair(num, 1));
} else{
mp[num]++;
}if(op == ';'){
cin >> num;
k = num;
break;
}
}
// 先建堆
map<int, int>::iterator iter;
for(iter = mp.begin(); iter != mp.end() && N < k; iter++){
shiftUpMin(q, iter->first, ++N);
}
while(iter != mp.end()){
if(iter->second > mp[q[1]]){
q[1] = iter->first;
fixMinHeap(q, 1, N);
}
iter++;
}
sort(q + 1, q + N + 1, cmp);
for(int i = 1; i <= N; i++){
cout << q[i] << endl;
}
}
合并两个有序数组
#include <iostream>
#include <map>
using namespace std;
int nums1[10005];
int nums2[10005];
struct BST{
int n;
BST *left;
BST *right;
};
void middle_order(BST *bst){
if(bst == nullptr){
return;
}
middle_order(bst->left);
cout << bst->n << " ";
middle_order(bst->right);
}
int main(){
int m, n;
BST *root = new BST;
root->left = nullptr;
root->right = nullptr;
cin >> m;
for(int i = 0; i < m; i++){
cin >> nums1[i];
}
cin >> n;
for(int i = 0; i < n; i++){
cin >> nums2[i];
}
if(m == 0 && n == 0) {
return 0;
} else if(m == 0){
for(int i = 0; i < n; i++){
cout << nums2[i] << " ";
}
return 0;
}else{
root->n = nums1[m / 2];
BST *cur = root;
for(int i = m / 2 - 1; i >= 0; i--){
BST *newNode = new BST;
newNode->left = nullptr;
newNode->right = nullptr;
newNode->n = nums1[i];
cur->left = newNode;
cur = newNode;
}
cur = root;
for(int i = m / 2 + 1; i < m; i++){
BST *newNode = new BST;
newNode->left = nullptr;
newNode->right = nullptr;
newNode->n = nums1[i];
cur->right = newNode;
cur = newNode;
}
//将num2添加至num1
for(int i = 0; i < n; i++){
BST *newNode = new BST;
newNode->left = nullptr;
newNode->right = nullptr;
newNode->n = nums2[i];
cur = root;
while (newNode->n <= cur->n){
if(cur->left == nullptr || newNode->n > cur->left->n){
newNode->left = cur->left;
cur->left = newNode;
break;
} else{
cur = cur->left;
}
}
while(newNode->n > cur->n){
if(cur->right == nullptr || newNode->n < cur->right->n ){
newNode->right = cur->right;
cur->right = newNode;
break;
}else{
cur = cur->right;
}
}
}
middle_order(root);
}
}
二分查找平方根
#include <iostream>
using namespace std;
int main(){
double n;
double precision = 0.0001;
cin >> n;
double left = 0, right = n, mid = (left + right) / 2;
while(abs(mid * mid - n) > precision){
if(mid * mid > n){
right = mid;
}else if(mid * mid < n){
left = mid;
}
mid = (left + right) / 2;
}
printf("%.4f", mid);
}
第五次作业
二分图判断
#include<iostream>
#include<queue>
using namespace std;
queue<int> q;
int currColor = 1;
int color[10005];//color单独定义,写在node中没用
struct Node{
int n;//每个桶的有效大小
Node* next;//后一个节点
};
struct AdjTable{//邻接链表
int cnt;//table的总数
Node *tables;
};
void add(Node *table, int v, int w){
Node *nodeV = new Node;
nodeV-> n = v;
nodeV->next = nullptr;
Node *curr = table + w - 1;//指向当前桶的指针
while(curr->next != nullptr) curr = curr->next;
curr->next = nodeV;
Node *nodeW = new Node;
nodeW-> n = w;
nodeW->next = nullptr;
curr = table + v - 1;//指向当前桶的指针
while(curr->next != nullptr) curr = curr->next;
curr->next = nodeW;
}
bool BFS_BIRPARTIE(Node *table, int s){
color[s] = currColor;
q.push(s);
int w;
while(!q.empty()){
w = q.back();
q.pop();
Node *curr = table + w - 1;
currColor = color[w];
while (curr->next != nullptr){
curr = curr->next;
if(color[curr->n] == 0){//看颜色就可以知道有没有访问过
// 注意这里错了!dummy存储的才是每个点的颜色,看链表里的新结点没用!
color[curr->n] = currColor * (-1);
q.push(curr->n);
}else{
if(color[w] == color[curr->n]){
return false;
}
}
}
}
return true;
}
int main()
{
int N, M;
cin >> N >> M;
AdjTable *adjTable = new AdjTable;
adjTable->cnt = N;
adjTable->tables = new Node[N];
Node *table = adjTable->tables;//指向邻接链表
for(int i = 0; i < N; i++){//给每个桶设一个dummy结点
table[i].n = i + 1;
table[i].next = nullptr;
}
int v, w;
// 构建邻接链表
for(int i = 0; i < M; i++){
cin >> v >> w;
add(table, v, w);
}
if(BFS_BIRPARTIE(table, 1)){
cout << "yes" << endl;
} else{
cout << "no" << endl;
}
}
拓扑排序
#include<iostream>
using namespace std;
int num[105];
int globalNum;
int vis[105];//color单独定义,写在node中没用
struct Node{
int n;//每个桶的有效大小
Node* next;//后一个节点
};
struct AdjTable{//邻接链表
int cnt;//table的总数
Node *tables;
};
void add(Node *table, int v, int w){//v->w
Node *nodeW = new Node;
nodeW-> n = w;
nodeW->next = nullptr;
Node *curr = table + v - 1;//指向当前桶的指针
while(curr->next != nullptr){
curr = curr->next;
if(curr->n == w){
break;
}
}
if(curr->next == nullptr){
curr->next = nodeW;
}
}
bool TOPO_ORDER(Node *table, int v){
vis[v - 1] = 1;
Node *curr = table + v - 1;
Node *tmp = curr;
while (tmp->next != nullptr){
tmp = tmp->next;
if(vis[tmp->n] == 0){
if(!TOPO_ORDER(table, tmp->n))
return false;
}else if(vis[tmp->n] == 1){
return false;
}
}
globalNum--;
num[globalNum] = v;
vis[v - 1] = 2;
return true;
}
bool TOPO_WRAPPER(Node *table, int n){
for(int i = 1; i <= n; i++){
if(vis[i - 1] == 0){
if(!TOPO_ORDER(table, i)){
return false;
}
}
}
return true;
}
//判断是不是有向无环图(没有BE)
int main()
{
int N, M;
while(true){//点的数量和边的数量
cin >> N >> M;
if(N == 0 && M == 0){
break;
}
globalNum = N + 1;
AdjTable *adjTable = new AdjTable;
adjTable->cnt = N;
adjTable->tables = new Node[N];
Node *table = adjTable->tables;//指向邻接链表
for(int i = 0; i < N; i++){//给每个桶的结点
table[i].n = i + 1;
table[i].next = nullptr;
}
int v, w;
// 构建邻接链表
for(int i = 0; i < M; i++){
cin >> v >> w;
add(table, v, w);
}
if(TOPO_WRAPPER(table, N)){
for(int i = 1; i <= N; i++){
cout << num[i] << " ";
}
cout << endl;
}else{
cout << "None!" << endl;
}
}
}
关键路径
还是看桶的第一个节点,不要看后面的关联节点。
#include<iostream>
using namespace std;
int num[10000005];
int maxEft;
int vis[10000005];//color单独定义,写在node中没用
struct Node{
int n;//每个桶的有效大小
int est;
int eft;
int safe_dis;
Node* next;//后一个节点
};
struct AdjTable{//邻接链表
int cnt;//table的总数
Node *tables;
};
void add(Node *table, int X, int Y, int Z){//X->Y
Node *nodeW = new Node;
nodeW-> n = Y;
nodeW->safe_dis = Z;
nodeW->eft = 0;
nodeW->est = 0;
nodeW->next = nullptr;
Node *curr = table + X;//指向当前桶的指针
while(curr->next != nullptr) curr = curr->next;
curr->next = nodeW;
}
bool TOPO_ORDER(Node *table, int v){
vis[v] = 1;
Node *curr = table + v;
Node *tmp = curr;
while (tmp->next != nullptr){
tmp = tmp->next;
if(vis[tmp->n] == 1){
return false;
}
Node *w = table + tmp->n;
if(w->est < max(curr->est + tmp->safe_dis, curr->eft)){
w->est = max(curr->est + tmp->safe_dis, curr->eft);
w->eft = w->est + 1;
if(w->eft > maxEft) maxEft = w->eft;
}
if(!TOPO_ORDER(table, w->n)){
return false;
}
}
vis[v] = 2;
return true;
}
bool TOPO_WRAPPER(Node *table, int n){
for(int i = 0; i < n; i++){
if(vis[i] == 0){
if(!TOPO_ORDER(table, i)){
return false;
}
}
}
return true;
}
//判断是不是有向无环图(没有BE)
int main()
{
int N, M;
while(cin >> N){
cin >> M;
AdjTable *adjTable = new AdjTable;
adjTable->cnt = N;
adjTable->tables = new Node[N];
Node *table = adjTable->tables;//指向邻接链表
for(int i = 0; i < N; i++){//给每个桶的结点
table[i].n = i;
table[i].est = 0;
table[i].eft = 0;
table[i].safe_dis = 0;
table[i].next = nullptr;
}
int X, Y, Z;
// 构建邻接链表
for(int i = 0; i < M; i++){
cin >> X >> Y >> Z;
add(table, X, Y, Z);
}
if(TOPO_WRAPPER(table, N)){
cout << maxEft << endl;
}else{
cout << "None!" << endl;
}
}
}
BCC数量
#include<iostream>
#include <stack>
using namespace std;
int back[105];
int vis[105];
int maxEft;
int discoverTime[105];//color单独定义,写在node中没用
stack<int> s;
int num;
int t;
struct Node{
int n;//每个桶的有效大小
Node* next;//后一个节点
};
struct AdjTable{//邻接链表
int cnt;//table的总数
Node *tables;
};
void add(Node *table, int x, int y){//x->y y->x
Node *nodeW = new Node;
nodeW-> n = y;
nodeW->next = nullptr;
Node *curr = table + x;
while(curr->next != nullptr) {
curr = curr->next;
if (curr->n == y){
break;
}
}
if(curr->n != y){
curr->next = nodeW;
}
Node *nodeV = new Node;
nodeV-> n = x;
nodeV->next = nullptr;
curr = table + y;//指向当前桶的指针
while(curr->next != nullptr) {
curr = curr->next;
if (curr->n == x){
break;
}
}
if(curr->n != x){
curr->next = nodeV;
}
}
void ARTICULATION_POINT_DFS(Node *table, int v){
vis[v] = 1;
t++;
discoverTime[v] = t;
back[v] = discoverTime[v];
Node *curr = table + v;
Node *tmp = curr;
while (tmp->next != nullptr){
tmp = tmp->next;
s.push(v * 10 + tmp->n);
if(vis[tmp->n] == 0){
ARTICULATION_POINT_DFS(table, tmp->n);
if(back[tmp->n] >= discoverTime[v]){
while(s.top() != v * 10 + tmp->n){
s.pop();
}
s.pop();
num++;
}
back[v] = min(back[v], back[tmp->n]);
} else if(vis[tmp->n] == 1){
back[v] = min(back[v], discoverTime[tmp->n]);
}
}
vis[v] = 2;
}
void WRAPPER(Node *table, int n){
for(int i = 0; i < n; i++){
if(vis[i] == 0){
ARTICULATION_POINT_DFS(table, i);
}
}
}
//判断是不是有向无环图(没有BE)
int main()
{
int N;
cin >> N;
AdjTable *adjTable = new AdjTable;
adjTable->cnt = N;
adjTable->tables = new Node[N];
Node *table = adjTable->tables;//指向邻接链表
for(int i = 0; i < N; i++){//给每个桶的结点
table[i].n = i;
table[i].next = nullptr;
}
int x, y;
while (cin >> x){
if(x == -1) break;
while(cin >> y){
if(y == -1) break;
add(table, x, y);
}
}
WRAPPER(table, N);
cout << num << endl;
}
SCC数量
#include<iostream>
#include <stack>
using namespace std;
int vis[105];
int vis2[105];//用于转置的情况
int num;
stack<int> s;
struct Node{
int n;//每个桶的有效大小
Node* next;//后一个节点
};
struct AdjTable{//邻接链表
int cnt;//table的总数
Node *tables;
};
void add(Node *table, int x, int y){//x->y
Node *nodeW = new Node;
nodeW-> n = y;
nodeW->next = nullptr;
Node *curr = table + x;
while(curr->next != nullptr) {
curr = curr->next;
if (curr->n == y){
break;
}
}
if(curr->n != y){
curr->next = nodeW;
}
}
void dfs(Node *table, int v, int vis[]){
vis[v] = 1;
Node *curr = table + v;
Node *tmp = curr;
while (tmp->next != nullptr){
tmp = tmp->next;
if(vis[tmp->n] == 0){
dfs(table, tmp->n, vis);
}
}
vis[v] = 2;
s.push(v);
}
Node* transpose(Node *table, int n){
Node *newTable = new Node[n];
for(int i = 0; i < n; i++){
newTable[i].n = i;
newTable[i].next = nullptr;
}
Node *curr, *tmp;
for(int i = 0; i < n; i++){
curr = table + i;
tmp = curr;
while (tmp->next != nullptr){
tmp = tmp->next;
add(newTable, tmp->n, curr->n);
}
}
delete[] table;
return newTable;
}
void SCC(Node *table, int n){
for(int i = 0; i < n; i++){
if(vis[i] == 0){
dfs(table, i, vis);
}
}
table = transpose(table, n);
while(!s.empty()){
int v = s.top();
s.pop();
if(vis2[v] == 0){
dfs(table, v, vis2);
num++;
}
}
}
//判断是不是有向无环图(没有BE)
int main()
{
int N;
cin >> N;
AdjTable *adjTable = new AdjTable;
adjTable->cnt = N;
adjTable->tables = new Node[N];
Node *table = adjTable->tables;//指向邻接链表
for(int i = 0; i < N; i++){//给每个桶的结点
table[i].n = i;
table[i].next = nullptr;
}
int x, y;
while (cin >> x){
if(x == -1) break;
while(cin >> y){
if(y == -1) break;
add(table, x, y);
}
}
SCC(table, N);
cout << num << endl;
}
第六次作业
修建公路
我使用了Kruskal算法求最短路径MST。
#include<iostream>
#include <algorithm>
using namespace std;
int root[5005];
struct Edge{//记录两个结点和边的长度
int u;
int v;
int cost;
};
bool cmp(Edge a, Edge b){
return a.cost < b.cost;
}
int find_root(int a){
while (a != root[a]){
a = root[a];
}
return a;
}
//判断是不是有向无环图(没有BE)
int main()
{
int N, M;//N是点的数量,M是边的数量
int mst = 0;
int edgeNum = 0;
cin >> N >> M;
//并查集初始化
for(int i = 1; i <= N; i++){
root[i] = i;
}
//初始化边
Edge *edge = new Edge[M];
int u, v, cost;
for(int i = 0; i < M; i++){
cin >> u >> v >> cost;
edge[i].u = u;
edge[i].v = v;
edge[i].cost = cost;
}
//生成MST
sort(edge, edge + M, cmp);
for(int i = 0; i < M; i++){
u = edge[i].u;
v = edge[i].v;
if(find_root(u) != find_root(v)){
root[v] = root[u];
mst += edge[i].cost;
edgeNum++;
if(edgeNum == N - 1){
break;
}
}
}
cout << mst << endl;
}
最短路径
// Dijkstra邻接矩阵
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;// 正无穷
const int Maxsize=5005;// 顶点数
int e[Maxsize][Maxsize];// 邻接矩阵
int book[Maxsize];// 标记是否被加入了最短路径表
int dis[Maxsize];// 距离表 记录点1到各点的最短距离
int n,m;// n:节点;m:边
int v1,v2,w;
int main()
{
cin >> n >> m;
// 初始化邻接矩阵
for(int i = 1;i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(i == j) e[i][j] = 0;
else e[i][j] = INF;
}
}
// 建立邻接矩阵
for(int i = 1; i <= m; i++)
{
cin >> v1 >> v2 >> w;
e[v1][v2] = w;
}
// 初始化源点1到各点的最短距离
for(int i=1;i<=n;i++)
{
dis[i]=e[1][i];
}
// 初始化各点是否被标记
for(int i = 1;i <= n; i++)book[i]=0;
book[1]=1;
for(int i = 1;i <= n-1; i++)// n-1次循环
{
// 找到距离1号顶点最近的顶点(min_index)
int min_num = INF;
int min_index = 0;
for(int k = 1;k <= n; k++)// n次循环
{
if(min_num > dis[k] && book[k] == 0)
{
min_num = dis[k];
min_index = k;
}
}
book[min_index] = 1;// 标记
// 更新与min_index有关的边
for(int j = 1;j <= n; j++)
{
// 如果节点min__index=>j 有边
if(e[min_index][j]<INF)
{
dis[j] = min(dis[j], dis[min_index] + e[min_index][j]);
}
}
}
cout << dis[n];
return 0;
}
分发饼干
#include <iostream>
#include <algorithm>
using namespace std;
int children[1005];
int cookie[1005];
int ans;
int n1, n2;
int main(){
int n;
char c;
while(cin >> n){
children[n1++] = n;
cin >> c;
if(c==';') {
break;
}
}
while(cin >> n){
cookie[n2++] = n;
cin >> c;
if(c != ',')break;
}
sort(children, children + n1);
sort(cookie, cookie + n2);
int index1 = 0, index2 = 0;
while (index1 < n1 && index2 < n2){
if(children[index1] <= cookie[index2]){
ans++;
index1++, index2++;
}else{
index2++;
}
}
cout << ans;
return 0;
}
补齐数组
https://blog.csdn.net/qq_41547882/article/details/111879937?spm=1001.2014.3001.5506
不断更新最大能表示的数字
最少操作数组递增
#include <iostream>
using namespace std;
int N;
int main(){
int n[1005];
int tmp = 0, ans = 0;
while(cin >> tmp) {
n[N++] = tmp;
}
for(int i = 0; i < N - 1; i++){
if(n[i + 1] <= n[i]){
ans += n[i] + 1 - n[i + 1];
n[i + 1] = n[i] + 1;
}
}
cout << ans << endl;
return 0;
}
第七次作业
农夫的牛棚
f[i][j] = 1 + min(min(f[i-1][j], f[i][j - 1]), f[i-1][j-1])
看能不能增加一行/一列/一对角
#include <iostream>
using namespace std;
char a[1005][1005];
int f[1005][1005];
int ans = 0;
int main(){
int N, T;
cin >> N >> T;
for(int i = 1; i <= N; i++){
for(int j = 1; j <= N; j++){
a[i][j] = '.';
}
}
for(int i = 0; i < T; i++){
int x, y;
cin >> x >> y;
a[x][y] = '#';
}
for(int i = 1; i <= N; i++){
for(int j = 1; j <= N; j++){
if(a[i][j] == '#'){
f[i][j] = 0;
}else{
if(i == 1 || j == 1){
f[i][j] = 1;
if(f[i][j] > ans){
ans = f[i][j];
}
}else{
f[i][j] = 1 + min(min(f[i-1][j], f[i][j - 1]), f[i-1][j-1]);
if(f[i][j] > ans){
ans = f[i][j];
}
}
}
}
}
cout << ans << endl;
return 0;
}
江洋大盗
#include <iostream>
using namespace std;
int shop[100005];
int dp[100005];
int ans = 0;
int main(){
int T;
cin >> T;
while(T > 0){
int N;
cin >> N;
for(int i = 1; i <= N; i++){
int money;
cin >> money;
shop[i] = money;
if(i == 1){
dp[i] = shop[i];
}else if(i == 2){
dp[i] = max(shop[i], dp[i - 1]);
}else{
//分为抢这家店,和不抢这家店
dp[i] = max(shop[i] + dp[i - 2], dp[i - 1]);
}
if(dp[i] > ans){
ans = dp[i];
}
}
cout << ans << endl;
T--;
ans = 0;
}
return 0;
}
最短路
#include <iostream>
using namespace std;
int dp[105];
int ans = 0;
int main(){
int N, M;
cin >> N >> M;
for(int i = 1; i < 105; i++){
dp[i] = 10000;//初始值赋个很大的数
}
while(N != 0){
dp[1] = 0;
for(int i = 1; i <= M; i++){
int a, b, c;
cin >> a >> b >> c;
if(a > b){
swap(a, b);
}
//不断更新最短路径
dp[b] = min(dp[b], dp[a] + c);
}
cout << dp[N] << endl;
cin >> N >> M;
}
return 0;
}
Wormholes
用floyed算法求负权环。注意每次都要初始化。
#include <iostream>
using namespace std;
int map[505][505];
const int INF = 99999999;
int main(){
int F, N, M, W, S, E, T;
cin >> F;
while(F > 0){
F--;
bool flag = false;
cin >> N >> M >> W;
for(int i = 1; i <= N; i++){//每个回合都要把数组清空
for(int j = 1; j <= N; j++){
if(i != j)map[i][j] = INF;
else map[i][j] = 0;
}
}
for(int i = 0; i < M; i++){//双向 输入路径
cin >> S >> E >> T;
map[S][E] = T;
map[E][S] = T;
}
for(int i = 0; i < W; i++){//单向 输入虫洞
cin >> S >> E >> T;
map[S][E] = (-1)*T;
}
//用floyed算法,看有没有负权环,如果有则为true
for(int k = 1; k <= N; k++){
for(int i = 1; i <= N; i++){
for(int j = 1; j <= N; j++){
if(map[i][j]>map[i][k]+map[k][j])
{
map[i][j]=map[i][k]+map[k][j];
}
}
if(map[i][i] < 0){//注意这里是(i,i)!和自己比!
flag = true;
break;
}
}
if(flag){
break;
}
}
if(flag){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
return 0;
}
牛棚(贪心)
#include <iostream>
#include <algorithm>
using namespace std;
int a[205];
int b[205];
const int INF = 99999999;
int main(){
int M, S, C;
cin >> M >> S >> C;
for(int i = 0; i < C; i++){
cin >> a[i];
}
sort(a, a + C);
for(int i = 0; i < C - 1; i++){
b[i] = a[i + 1] - a[i] - 1;//记录每个牛棚间的间隔(即空的牛棚)
}
sort(b, b + C - 1);//对间隔进行排序
int ans = 0;
for(int i = 0; i < C - M; i++){
ans += b[i];//把需要挡住的间隔加上
}
cout << ans + C << endl;//注意输出的是模板总长度!C肯定是要有的长度,ans是额外要挡住的间隔,因为木板数量不够
return 0;
}
第八次作业
坏计算器
双倍(Double):将显示屏上的数字乘 2;
递减(Decrement):将显示屏上的数字减 1 。
最初,计算器显示数字 X。
返回显示数字 Y 所需的最小操作数。
逆向思维:Y比X大,Y到X的最小操作数。
当 Y 是偶数,如果先执行 2 次加法操作,再执行 1 次除法操作,我们可以通过先执行 1 次除法操作,再执行 1 次加法操作以使用更少的操作次数得到相同的结果 [(Y+2) / 2 vs Y/2 + 1]。
而当 Y 是奇数,如果先执行 3 次加法操作,再执行 1 次除法操作,我们可以将其替代为顺次执行加法、除法、加法操作以使用更少的操作次数得到相同的结果 [(Y+3) / 2 vs (Y+1) / 2 + 1]。
所以无论如何,奇数先加,偶数先除比较方便。
#include <iostream>
using namespace std;
int main(){
int X, Y;
char c;
cin >> X >> c >> Y;
int ans = 0;
while(Y > X) {
ans++;
if (Y%2 == 1) Y++;
else Y /= 2;
}
cout << ans + X - Y;
return 0;
}
摆动序列
up[i] 表示以前 i 个元素中的某一个为结尾的最长的「上升摆动序列」的长度。
down[i] 表示以前 i 个元素中的某一个为结尾的最长的「下降摆动序列」的长度。
由此列出状态转移方程。
#include <iostream>
#include <vector>
using namespace std;
int up[105];
int down[105];
vector<int> nums;
int main(){
char c;
int n;
while(cin >> n){
nums.push_back(n);
cin >> c;
}
for(int i = 0; i < nums.size(); i++){
if(i == 0){
up[0] = down[0] = 1;
}else{
if (nums[i] > nums[i - 1]) {
up[i] = max(up[i - 1], down[i - 1] + 1);
down[i] = down[i - 1];
} else if (nums[i] < nums[i - 1]) {
up[i] = up[i - 1];
down[i] = max(up[i - 1] + 1, down[i - 1]);
} else {
up[i] = up[i - 1];
down[i] = down[i - 1];
}
}
}
cout << max(up[nums.size() - 1], down[nums.size() - 1]);
return 0;
}
翻转对
注意统计翻转对和归并的过程不在一起。
把下标改成从0开始莫名就好了。
#include <iostream>
using namespace std;
long long int a[105], temp[105];//用全局变量传参时简单很多
long long int tot = 0;//翻转对个数
void f(int m, int n){
if(m == n)return;
long long int mid = (m + n) / 2;
f(m, mid);
f(mid + 1, n);//对左右进行归并排序,使均为升序
long long int i = m;//从左边的第一个元素开始
long long int j = mid + 1;//从右边的第一个元素开始
long long int now = m;//temp现在的指针
while (i <= mid && j <= n){//这里只能统计翻转对,不能统计归并
if(a[i] > 2 * a[j]){
tot += mid + 1 - i;//注意不是j - i!!!
j++;
} else{
i++;
}
}
i = m, j = mid + 1;
while (i <= mid && j <= n){//进行归并排序
if(a[i] <= a[j]){
temp[now++] = a[i++];
} else{
temp[now++] = a[j++];
}
}
while (i <= mid){
temp[now++] = a[i++];
}
while (j <= n){
temp[now++] = a[j++];
}
for(i = m; i <= n; i++){
a[i] = temp[i];
}
}
int main(){//归并排序的过程中求逆序对
long long int n = 0;
int cnt = 0;
char c;
while(cin >> n){
a[cnt++] = n;
cin >> c;
}
f(0, cnt - 1);//因为这里不是全局变量,所以要传参
cout << tot;
return 0;
}
相似度为k的字符串
如果可以通过将 A 中的两个小写字母精确地交换位置 K 次得到与 B 相等的字符串,我们称字符串 A 和 B 的相似度为 K(K 为非负整数)。
给定两个字母异位词 A 和 B ,返回 A 和 B 的相似度 K 的最小值。示例 1:
输入:ab,ba
输出:1
#include <iostream>
#include <cstring>
using namespace std;
int res = 0;//最小的变化次数
int len = 0;
void dfs(string &A, string &B, int pos, int step){//step表示当前方式下的步数
if(step >= res){//这种方式可以不要了
return;
}
if(pos == len){
res = min(res, step);//这种情况也到最后了
return;
}
if(A[pos] == B[pos]){//当前位置不变
dfs(A, B,pos + 1, step);
}
else{
for(int i = pos + 1; i < len; i++){
if(A[i] == B[pos] && A[i] != B[i]){//合适的供变换的地方
swap(A[i],A[pos]);
dfs(A,B,pos + 1,step + 1);//试试这种方法
swap(A[i],A[pos]);//还原
}
}
}
}
int main(){
string A, B, tmp;
cin >> tmp;
int index = tmp.find(",");
A = tmp.substr(0, index);
B = tmp.substr(index + 1, tmp.size() - index);
len = A.length();
res = len + 1;//最大的变换次数就是len-1,所以赋len+1肯定没事
dfs(A, B, 0, 0);//因为这里不是全局变量,所以要传参
cout << res << endl;
return 0;
}
连续子序列的和
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
#include <iostream>
#include <vector>
using namespace std;
vector<int> nums;
int main(){
int n;
while(cin >> n){
nums.push_back(n);
}
int max = 0;
int now = 0;
for(int i = 0; i < nums.size(); i++){
now += nums[i];
if(now >= 0){
if(now > max){
max = now;
}
}else{
now = 0;
}
}
cout << max;
return 0;
}