2022春算法OJ

写在前面:只是通过了平台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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值