PAT考前总复习

⛵️PAT总复习

​ 这篇文章是关于一个PAT的总复习,整理以备复习参考。可能包含不全,我列出了一些易错点

🏖1.多项式

甲级1002.A+B for Polynomials题,多项式中,个人认为,多项式用最快的方法就是map进行存储,然后进行依次打印。(1009.Product of Polynomials,多项式乘法也可以用该方法做)

题意:给出2个多项式,输出和。模板案例如下:

#include <iostream>
#include <map>
using namespace std;
int main()
{
    int M, coef, coun=2;
    double expo;
    map<int, double, greater<int>> m;
    while(coun--){
        cin >> M;
        while(M--){
            cin >> coef >> expo;
            m[coef] += expo;
        }
    }
    for(auto it = m.begin(); it != m.end(); it++)
        if(it -> second == 0) m.erase(it);
    cout << m.size();
    for(auto it: m)
        printf(" %d %.1f", it.first, it.second);
    return 0;
}

🏝2.素数

素数考察主要是素数判别,可能会加上一些其他基础逻辑。参考1015.Reversible Primes, 1152.Google Recruitment

素数的判别写法如下:

bool isPrime(int N){
    if(N <= 1) return false;
    for(int i = 2; i * i <= N; i++)
        if(N % i ==0) return false;
    return true;
}

🏜3.Java优先题型

大数字题型

​ 大数字,考试就不要想***钻的方法了,平时练习可以考虑cpp如何处理,也不要想范围,就直接用Java语言进行处理。

如:1065 a+b(64 bit)

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		BigInteger A, B, C;
		for(int i = 1; i <= N; i++) {
			A = sc.nextBigInteger();
			B = sc.nextBigInteger();
			C = sc.nextBigInteger();
			if(A.add(B).compareTo(C)>0)
				System.out.printf("Case #%d: true\n", i);
			else
				System.out.printf("Case #%d: false\n", i);
		}
	}
}
一眼看上去就很方便的题型

如:1024.Palindromic Number

import java.math.BigInteger;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        BigInteger b = sc.nextBigInteger();
        int cnt = sc.nextInt(), i;
        for(i = 0; i < cnt; i++) 
            if(b.toString().equals(new StringBuilder(b.toString()).reverse().toString())) break;
            else b = new BigInteger(new StringBuilder(b.toString()).reverse().toString()).add(b);
        System.out.println(b + "\n" + i);
    }
}

⛳︎4.链表Vector模拟

​ 反转链表往往用struct node{} 会比较浪费脑力,如果遇到了,统一使用unodered_map进行寻址,如:1074.Reversing Linked List

#include "iostream"
#include "vector"
#include "map"
using namespace std;
// 使用一个三元组node进行存储元素
struct node {
    int val, addr, next;
}tmp;
// 一定要方便逻辑处理,一般不会超空间,可以多遍历几次筛选
vector<node> v, tmp_v, ans; 
// 这题使用map不会超时,如果超时,使用unordered_map
map<int, node> m;
int main() {
    int start, N, K;
    scanf("%d%d%d", &start, &N, &K);
    for(int i = 0; i < N; i++) { // 读数
        scanf("%d%d%d", &tmp.addr, &tmp.val, &tmp.next);
        m[tmp.addr] = tmp;
    }
    while(start != -1) { // 顺序化链表
        v.push_back(m[start]);
        start = m[start].next;
    }
    for(int i = 0; i < v.size(); i++) {
        tmp_v.push_back(v[i]); 
        if(tmp_v.size() == K) { // k个反转
            for(int j = tmp_v.size() - 1; j >= 0; j--)
                ans.push_back(tmp_v[j]);
            tmp_v.clear();
        }
    }
    for(int  i = 0; i < tmp_v.size(); i++) 
        ans.push_back(tmp_v[i]); // 剩余顺序放入
    for(int i = 0; i < ans.size(); i++)  // 打印
        if(i == 0) printf("%05d %d", ans[i].addr, ans[i].val);
        else printf(" %05d\n%05d %d", ans[i].addr, ans[i].addr, ans[i].val);
    if(ans.size() != 0) printf(" -1");
    return 0;
}

⛽︎5.精度问题

​ 例如1070.Mooncake,需要进行精度计算的题目,我们统一把所有变量都定义为double,一般情况能过。(如果还是精度不够,可以尝试将数字扩大1000倍,进行计算后,最后再统一除以1000。如果不想思考了,可以尝试使用Java的BigDecimal,那个更为精准)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 这边变量定义为double
struct mooncake {
    double cnt, price;
};
vector<mooncake> v;
bool cmp(mooncake mc, mooncake mc2) {
    return mc.price * mc2.cnt < mc2.price * mc.cnt;
}
int main() {
    // 考试很紧张,遇到精度题,所有都定义为double吧。嘿嘿,不要思考啦。
    double N, target;
    scanf("%lf %lf", &N, &target);
    v.resize(N);
    for(int i = 0; i < N; i++)
        scanf("%lf", &v[i].price);
    for(int i = 0; i < N; i++)
        scanf("%lf", &v[i].cnt);
    sort(v.begin(), v.end(), cmp);
    double ans = 0;
    for(int i = 0; i < N && target != 0; i++){
        if(v[i].price <= target){
            target -= v[i].price;
            ans += v[i].cnt;
        }else {
            ans += (target * v[i].cnt / v[i].price);
            target = 0;
        }
    }
    printf("%.2f", ans);
    return 0;
}

⛺︎6.大规模计数

​ 如:1093. Count PATs,整个题库中仅有的1题,印象深刻,我们需要用到一组串中的前后进行累乘的,可以通过1次遍历进行计算总数,然后第二次遍历,进行前加后减的方法进行。

​ 这里提到的第一点是前加后减的方法(虽然再遇到可能性不大),但是我们记得在每步运算都加上 %1000000007

#include <iostream>
using namespace std;
int main()
{
    string s;
    getline(cin, s);
    long long P = 0, A = 0, T = 0, sum = 0;
    for(int i = 0; i < s.length(); i++)
        if(s[i] == 'T') T++;
    for(int i = 0; i < s.length(); i++){
        if(s[i] == 'P') P++;
        if(s[i] == 'T') T--;
        if(s[i] == 'A') sum += ((P % 1000000007 * T % 1000000007) % 1000000007);
    }
    cout << sum % 1000000007;
    return 0;
}

⛲7.最大公因数

最大公因数的模板如下,当n2为0的时候,返回n1,否则返回递归gcd(n2, n1 % n2)

/** 最大公约数 */
long long gcd(long long n1, long long n2) {
    return n2 == 0 ? n1 : gcd(n2, n1 % n2);
}

除了这个方法,介绍一个很方便的内置函数。

在windows和linux下的<algorithm>中含有一个内置函数,__gcd(x, y),我们仅仅需要使用这个内置函数即可完成gcd,但是这个函数在mac下不支持。

#include <algorithm>
cout << __gcd(3, 6); // 直接使用内置函数

⛪︎8.螺旋矩阵

螺旋矩阵,我们通过一个设计模式书上的案例即可达到。我们定义一个方向变量dir,进行模拟旋转方向,然后每次移动一次move()1105.Spiral Matrix代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N;
int main() {
    scanf("%d", &N);
    vector<int> v(N);
    for(int i = 0; i < N; i++)
        scanf("%d", &v[i]);
    sort(v.begin(), v.end(), greater<int>());
    int col, row;
    for(int i = 1; i * i <= N; i++)
        if(N % i == 0) col = i;
    row = N / col;
    vector<vector<int>> ans(row);
    for(int i = 0; i < row; i++) ans[i].resize(col, -1);
    int x = 0, y = 0, dir = 0, i = 0;// 0 右边 1 下面 2 左面 3 上面
    if(y + 1 >= col || ans[x][y + 1] != -1) dir = (dir + 1) % 4; // 开始方向可能朝下
    while(true) {
        if(i == v.size()) break;
        if(dir == 0) {
            ans[x][y++] = v[i++]; 
            if(y + 1 >= col || ans[x][y + 1] != -1) dir = (dir + 1) % 4;
        } else if(dir == 1) {
            ans[x++][y] = v[i++];
            if(x + 1 >= row || ans[x + 1][y] != -1) dir = (dir + 1) % 4;
        } else if(dir == 2) {
            ans[x][y--] = v[i++];
            if(y - 1 < 0 || ans[x][y - 1] != -1) dir = (dir + 1) % 4;
        } else {
            ans[x--][y] = v[i++];
            if(x - 1 < 0 || ans[x - 1][y] != -1) dir = (dir + 1) % 4;
        }
    }
    for(int i = 0; i < row; i++) {
        printf("%d", ans[i][0]);
        for(int j = 1; j < col; j++) 
            printf(" %d", ans[i][j]);
        putchar('\n');
    }
    return 0;
}

⛄︎9.暴力递归

​ 写递归题需要注意,在去年9月真题的第一题15分的forever,就要求写暴力递归。后来我在题库中也找到一题需要写暴力递归的。

​ 暴力递归的主要核心是:

  • 1.进行拆解条件,我们选择脑海中觉得复杂度最低的条件,进行构建函数,进行暴力递归。
  • 2.剪枝,剪枝也就是所谓的写循环出口,我们可以写一些没必要的条件中立马让递归进行return,这样能够打打降低算法的复杂度。

下题为题库的1103.Integer Factorization

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int N, K, P, maxFacSum = -1;
vector<int> v, ans, tmpAns;
void init() {
    int tmp = 0, index = 1;
    while(tmp <= N) {
        v.push_back(tmp);
        tmp = pow(index++, P);
    }
}
void dfs(int index, int tmpSum, int tmpK, int facSum) {
    if(tmpK == K) {
        if(tmpSum == N && facSum > maxFacSum) {
            ans = tmpAns;
            maxFacSum = facSum;
        }
        return;
    }
    while(index >= 1) {
        if(tmpSum + v[index] <= N) {
            tmpAns[tmpK] = index;
            dfs(index, tmpSum + v[index], tmpK + 1, facSum + index);
        } 
        if(index == 1) return;
        index--;
    }
}
int main() {
    scanf("%d%d%d", &N, &K, &P);
    init();
    tmpAns.resize(K);
    dfs(v.size() - 1, 0, 0, 0);
    if(maxFacSum == -1) printf("Impossible");
    else {
        printf("%d = ", N);
        for(int i = 0; i < ans.size(); i++) {
            if(i != 0) printf(" + ");
            printf("%d^%d", ans[i], P);
        }
    }
    return 0;
}

⭐︎10.Hashing

虽然有线性探测 和 平方探测,不变的点是查找要多查一次。

线性探测法,参考Data Structures and Algorithms(English) 7-18 Hashing - Hard Version(30')

#include <iostream>
#include <vector>
#include <map>
#include <set>
using namespace std;
map<int, set<int>> G;
map<int, int> degree;
int main() {
    int N, tmp, cnt = 0;
    scanf("%d", &N);
    vector<int> v(N), ans;
    for(int i = 0; i < N; i++) {
        scanf("%d", &v[i]);
        if(v[i] > 0) {
            degree[v[i]] = 0; // 入度设置为0
            cnt++;
        }
    }
    for(int i = 0; i < N; i++) {
        if(v[i] > 0) {
            int tmp = v[i];
            while(tmp % N != i) {
                G[v[tmp % N]].insert(v[i]);
                tmp++;
                degree[v[i]]++;
            }
        }
    }
    int index = 0;
    while(index != cnt) {
        int min;
        for(auto x: degree) {
            if(x.second == 0) {
                min = x.first;
                break;
            }
        }
        degree[min]--;
        for(auto x: G[min]) degree[x]--;
        ans.push_back(min);
        index++;
    }
    printf("%d", ans[0]);
    for(int i = 1; i < cnt; i++)
        printf(" %d", ans[i]);
    return 0;
}

平方探测法,参考 1145 Hashing - Average Search Time

#include <iostream>
#include <vector>
using namespace std;
bool isPrime(int N) {
    if(N <= 1) return false;
    for(int i = 2; i * i <= N; i++)
        if(N % i == 0) return false;
    return true;
}
int main() {
    int MSize, N, M, tmp;
    cin >> MSize >> N >> M;
    while(!isPrime(MSize)) MSize++;
    vector<int> hash(MSize, 0);
    while(N--) {
        cin >> tmp;
        int flag = true;
        for(int i = 0; i < MSize; i++) {
            if(hash[(tmp + i * i) % MSize] == 0) {
                hash[(tmp + i * i) % MSize] = tmp;
                flag = false;
                break;
            }
        }
        if(flag) printf("%d cannot be inserted.\n", tmp);
    }
    int cnt = 0;
    for(int c = 0; c < M; c++) {
        cin >> tmp;
        for(int i = 0; i <= MSize; i++) {
            cnt++;
            if(hash[(tmp + i * i) % MSize] == tmp ||
                hash[(tmp + i * i) % MSize] == 0) 
                break;
        }
    }
    printf("%.1lf", (double)cnt / M);
    return 0;
}

⛅︎11.二叉树中序遍历

参考 1064. Complete Binary Search Tree

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N, index_v = 0 ;
vector<int> v, res;
void inorder(int index_res){
    if(index_res >= N) return;
    inorder(2 * index_res + 1);
    res[index_res] = v[index_v++];
    inorder(2 * index_res + 2);
}
int main(){
    cin >> N;
    v.resize(N);
    res.resize(N);
    for(int i = 0; i < N; i++)
        cin >> v[i];
    sort(v.begin(),v.end());
    inorder(0);
    cout << res[0];
    for(int i = 1; i < N; i++)
        cout << " " << res[i];
    return 0;
}

🧆12.AVL模板

参照1066. Root of AVL Tree,记忆一遍,实在不行,找中位数,也能拿到大半分。

#include "iostream"
using namespace std;
struct node {
    int val;
    node *left, *right;
    node(int v):val(v), left(NULL), right(NULL) {}
} *root;
// get height
int get_height(node* root) {
    if(!root) return 0;
    return max(get_height(root->left), get_height(root->right)) + 1;
}
// Single Left Rotation
node* single_left_rotation(node* root) {
    node* tmp = root->left;
    root->left = tmp->right;
    tmp->right = root;
    return tmp;
}
// Single Right Rotation
node* single_right_rotation(node* root) {
    node* tmp = root->right;
    root->right = tmp->left;
    tmp->left = root;
    return tmp;
}
//  Double Left Right Rotation
node* double_left_right_rotation(node* root) {
    root->left = single_right_rotation(root->left);
    return single_left_rotation(root);
}
// Double Right left Rotation
node* double_right_left_rotation(node* root) {
    root->right = single_left_rotation(root->right);
    return single_right_rotation(root);
}
// insert
node* insert(node* root, int data) {
    if(root == NULL) root = new node(data);
    else if(data < root->val) {
        root->left = insert(root->left, data);
        if(get_height(root->left) - get_height(root->right) == 2) {
            if(data < root->left->val) root = single_left_rotation(root);
            else root = double_left_right_rotation(root); 
        }
    } else {
        root->right = insert(root->right, data);
        if(get_height(root->right) - get_height(root->left) == 2) {
            if(data > root->right->val) root = single_right_rotation(root);
            else root = double_right_left_rotation(root);
        }
    }
    return root;
}
int main() {
    int N, tmp;
    scanf("%d", &N);
    while(N--) {
        scanf("%d", &tmp);
        root = insert(root, tmp);
    }
    printf("%d", root->val);
    return 0;
}

🥝13.建树问题

前中建树:

void pre(int root, int start, int end) {
    if(start > end) return ;
    int i = start;
    while(i < end && in[i] != post[root]) i++;
    printf("%d ", post[root]);
    pre(root - 1 - end + i, start, i - 1);
    pre(root - 1, i + 1, end);
}

后中建树:

void post(int root, int start, int end) {
    if(start > end) 
        return ;
    int i = start;
    while(i < end && in[i] != pre[root]) i++;
    post(root + 1, start, i - 1);
    post(root + 1 + i - start, i + 1, end);
    printf("%d ", pre[root]);
}

层中建树:

node* build(int level_left, int level_right, int in_left, int in_right) {
    if(in_left > in_right) return NULL;
    int k, flag = 0;
    while(level_left <= level_right) {
        for(k = in_left; k <= in_right; k++)
            if(in[k] == level[level_left]) {
                flag = 1;
                break;
            }
        if(flag) break;
        level_left++;
    }
    node *n = new node(in[k]);
    n->left = build(level_left + 1, level_right, in_left, k - 1);
    n->right = build(level_left + 1, level_right, k + 1, in_right);
    return n;
}

先后建树(其中一种):

node *build(int pre_l, int pre_r, int post_l, int post_r) {
    if(pre_l > pre_r) return NULL;
    if(pre_l == pre_r) return new node(pre[pre_l]);
    node *n = new node(pre[pre_l]);
    int k = post_l;
    while(k < post_r && post[k] != pre[pre_l + 1]) k++;
    n->left = build(pre_l + 1, pre_l + 1 + k - post_l, post_l , k - 1);
    n->right = build(pre_l + 1 + k - post_l + 1, pre_r, k + 1, post_r - 1);
    return n;
}

🍑14.层序遍历

建树和层序遍历和中序遍历,都在1099 Build A Binary Search Tree

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
struct node {
    int data, left, right;
}tree[99999];
int ele[99999], N, l, r, ele_i = 0, start = true;
void inorder(int root) {
    if(tree[root].left !=  -1) inorder(tree[root].left);
    tree[root].data = ele[ele_i++];
    if(tree[root].right !=  -1) inorder(tree[root].right);
}
void levelorder(int root) {
    queue<int> que;
    que.push(root);
    while(!que.empty()) {
        node n = tree[que.front()];
        if(start) printf("%d", n.data);
        else printf(" %d", n.data);
        start = false;
        que.pop();
        if(n.left != -1) que.push(n.left);
        if(n.right != -1) que.push(n.right);
    }
}
int main() {
    scanf("%d", &N);
    for(int i = 0; i < N; i++) scanf("%d%d", &tree[i].left, &tree[i].right); 
    for(int i = 0; i < N; i++) scanf("%d", &ele[i]);
    sort(ele, ele + N);
    inorder(0);
    levelorder(0);
    return 0;
}

🏠15.反转二叉树

只要输入的时候,反着输入即可。参考1102 Invert a Binary Tree

#include "iostream"
#include "vector"
#include "string"
#include "queue"
using namespace std;
int N;
string tmp_l, tmp_r;
struct node {
    int data, left = -1, right = -1, level;
};
vector<node> v;
void levelorder(int root) {
    bool start = true;
    queue<node> que;
    que.push(v[root]);
    while(!que.empty()) {
        node n = que.front();
        if(start) {
            printf("%d", n.data);
            start = false;
        } else printf(" %d", n.data);
        que.pop();
        if(n.left != -1) que.push(v[n.left]);
        if(n.right != -1) que.push(v[n.right]);
    }
}      
bool start = true;
void inorder(int root) {
    if(v[root].left != -1) inorder(v[root].left);
    if(start) {
        start = !start;
        printf("%d", v[root].data);
    } else printf(" %d", v[root].data);
    if(v[root].right != -1) inorder(v[root].right);
}
int main() {
    scanf("%d", &N);
    v.resize(N);
    vector<bool> judge(N, false);
    for(int i = 0;i < N; i++) {
        cin >> tmp_l >> tmp_r;
        v[i].data = i;
        if(tmp_l != "-") {
            v[i].right = stoi(tmp_l);
            judge[stoi(tmp_l)] = true;
        }
        if(tmp_r != "-") {
            v[i].left = stoi(tmp_r);
            judge[stoi(tmp_r)] = true;
        }
    }
    int root_index;
    for(int i = 0; i < N; i++)
        if(judge[i] == false) root_index = i;
    levelorder(root_index);
    putchar('\n');
    inorder(root_index);
    return 0;
}

🏡16.完全二叉树

完全二叉树的判定就是:层序遍历,出现间断则不是完全二叉树。

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct node {
    int v;
    string left, right;
}n[30];
int N, root = 0, last;
bool isComplete(int root) {
    queue<int> que;
    que.push(root);
    bool flag = 1, ret = true;
    while(!que.empty()) {
        node tmp = n[que.front()];
        que.pop();
        last = tmp.v;
        if(tmp.left != "-") que.push(stoi(tmp.left));
        if(tmp.right != "-") que.push(stoi(tmp.right));
        if(flag) {
            if(tmp.left != "-" && tmp.right != "-") {
            } else if(tmp.left != "-") {
                flag = 0;
            } else if(tmp.right != "-") {
                ret = false;
            } else {
                flag = 0;
            }
        } else {
            if(tmp.left != "-" || tmp.right != "-") ret = false;
        }
    }
    return ret;
}
int main() {
    cin >> N;
    vector<int> find_root(N, 0);
    for(int i = 0; i < N; i++) {
        n[i].v = i;
        cin >> n[i].left >> n[i].right;
        if(n[i].left != "-") find_root[stoi(n[i].left)] = 1;
        if(n[i].right != "-") find_root[stoi(n[i].right)] = 1;
    }
    while(root < N && find_root[root]) root++;
    bool complete = isComplete(root);
    printf("%s %d\n", complete ? "YES": "NO", complete ? last: root);
    return 0;
}

🏘17.lca算法

lca的算法是进行写递归,分为2个算法。

// lca_bst
node *lca_bst(node *n, node *p, node *q) {
    if((n->val - p->val) * (n->val - q->val) <= 0) return n;
    else if(n->val < p->val && n->val < q->val) return lca_bst(n->right, p, q);
    else return lca_bst(n->left, p ,q);
}
// lca_common
node* lca_common(node *n, node *p, node *q) {
    if (n == NULL) return NULL;
    if (n->val == p->val || n->val == q->val) return n;
    node *left = lca_common(n->left, p, q);
    node *right = lca_common(n->right, p, q);
    if (left != NULL && right != NULL) return n;
    if (left != NULL) return left;
    if (right != NULL) return right;
    return NULL;
}

🐶18.Dijkstra模板

Dijkstra

#include <iostream>
#include <algorithm>
using namespace std;
int n, m, c1, c2;
int edge[510][510], weight[510], dis[510], num[510], w[510];
bool vis[510];
const int inf = 99999999;
int main() {
    scanf("%d%d%d%d", &n, &m, &c1, &c2);
    for(int i = 0; i < n; i++)
        scanf("%d", &weight[i]);
    fill(edge[0], edge[0] + 510 * 510, inf);
    fill(dis, dis + 510, inf);
    int a, b, c;
    for(int i = 0; i < m; i++){
        scanf("%d%d%d", &a, &b, &c);
        edge[a][b] = edge[b][a] = c;
    }
    dis[c1] = 0;
    w[c1] = weight[c1];
    num[c1] = 1;
    while(true) {
        int u = -1, minn = inf;
        for(int j = 0; j < n; j++){
            if(vis[j] == false && dis[j] < minn) {
                u = j;
                minn = dis[j];
            }
        }
        if(u == -1) break;
        vis[u] = true;
        for(int  v = 0; v < n; v++) {
            if(vis[v] == false && edge[u][v] != inf) {
                if(dis[u] + edge[u][v] < dis[v]) {
                    dis[v] = dis[u] + edge[u][v];
                    num[v] = num[u];
                    w[v] = w[u] + weight[v];
                }else if(dis[u] + edge[u][v] == dis[v]) {
                    num[v] = num[v] + num[u];
                    if(w[u] + weight[v] > w[v])
                        w[v] = w[u] + weight[v];
                }
            }
        }
    }
    printf("%d %d", num[c2], w[c2]);
    return 0;
}

Dijkstra堆优化

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n, m, c1, c2;
int edge[510][510], weight[510], dis[510], num[510], w[510];
bool vis[510];
const int inf = 99999999;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
int main() {
    scanf("%d%d%d%d", &n, &m, &c1, &c2);
    for(int i = 0; i < n; i++)
        scanf("%d", &weight[i]);
    fill(edge[0], edge[0] + 510 * 510, inf);
    fill(dis, dis + 510, inf);
    int a, b, c;
    for(int i = 0; i < m; i++){
        scanf("%d%d%d", &a, &b, &c);
        edge[a][b] = edge[b][a] = c;
    }
    dis[c1] = 0;
    w[c1] = weight[c1];
    num[c1] = 1;
    q.push({0, c1});
    while(q.size()) {
        // 改为了弹出
        int u = q.top().second;
        q.pop();
        // 如果已经访问,这边记得进行continue操作
        if(vis[u]) continue;
        vis[u] = true;
        for(int  v = 0; v < n; v++) {
            if(vis[v] == false && edge[u][v] != inf) {
                if(dis[u] + edge[u][v] < dis[v]) {
                    dis[v] = dis[u] + edge[u][v];
                    num[v] = num[u];
                    w[v] = w[u] + weight[v];
                }else if(dis[u] + edge[u][v] == dis[v]) {
                    num[v] = num[v] + num[u];
                    if(w[u] + weight[v] > w[v])
                        w[v] = w[u] + weight[v];
                }
                q.push({dis[v], v});
            }
        }
    }
    printf("%d %d", num[c2], w[c2]);
    return 0;
}

Bellman-Ford把普通Dijstra其中的贪心思想换成2重遍历即可,SPFA把Bellman-Ford进行堆优化即可。

Floyd算法:多源短路问题

void Floyd(){
	for(k = 0; k < N; k++)
		for(i = 0; i < N; i++)
			for(j = 0; j < N; j++)
				if(D[i][k] + D[k][j] < D[i][j]) {
					D[i][j] = D[i][k] + D[k][j];
					path[i][j] = k;
				}
}

🛕19.Prim&Kruskal

参照数据结构题集7-11

Prim:

#include <iostream>
#include <queue>
#include <vector>
#define INF 999999
using namespace std;
int N, M, a, b, c;
int e[1010][1010] = {0}, dist[1010], vis[1010] = {0};
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
int main() {
    scanf("%d%d", &N, &M);
    while(M--) {
        scanf("%d%d%d", &a, &b, &c);
        e[a][b] = e[b][a] = c;
    }
    fill(dist, dist + 1010, INF);
    dist[1] = 0;
    q.push({0, 1});
    while(q.size()) {
        int u = q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int v = 1; v <= N; v++) {
            if(!vis[v] && e[u][v] && dist[v] > e[u][v])  {
                dist[v] = e[u][v]; 
                q.push({dist[v], v});
            }
        }
    }
    int sum = 0, conn = 1;
    for(int i = 1; i <= N; i++) {
        sum += dist[i];
        if(!vis[i]) conn = 0;
    }
    if(!conn) printf("-1\n");
    else printf("%d\n", sum);
    
    return 0;
}

Kruskal:

#include <iostream>
#include <queue>
#include <vector>
#define INF 999999
using namespace std;
int N, M, a, b, c;
int vis[1010] = {0};
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
int main() {
    scanf("%d%d", &N, &M);
    while(M--) {
        scanf("%d%d%d", &a, &b, &c);
        q.push({c, a * 10000 + b});
    }
    int sum = 0, conn = 1;
    while(q.size()) {
        int m = q.top().second / 10000;
        int n = q.top().second % 10000;
        if(!vis[m] || !vis[n]) {
            sum += q.top().first;
            vis[m] = vis[n] = 1;
        }
        q.pop();
    }
    printf("%d\n", sum);
    return 0;
}
posted @ 2020-07-22 07:10  SteveYu  阅读(620)  评论(2编辑  收藏  举报