自用算法模板(JAVA版)

一、數(shù)論

1)GCD

GCD(求最大公約數(shù))

public static int gcd(int a, int b) {
    if(b == 0) return a;
    return gcd(b, a%b);
}

QGCD(快速GCD)

public static int qGCD(int a, int b) {
    if(a == 0) return b;
    if(b == 0) return a;
    if((a & 1) == 0 && (b & 1) == 0) {
        return qGCD(a >> 1, b >> 1) << 1;
    } else if((b & 1) == 0) {
        return qGCD(a, b >> 1);
    } else if((a & 1) == 0) {
        return qGCD(a >> 1, b);
    } else {
        return qGCD(Math.abs(a - b), Math.min(a, b));
    }
}

extGCD(拓展GCD,解決ax + by = c 問題)

import java.util.Scanner;

public class 數(shù)論_拓展GCD {
    /**
     *  題目描述:
     *  兩只青蛙在網(wǎng)上相識(shí)了,它們聊得很開心,于是覺得很有必要見一面。它們很高興地發(fā)現(xiàn)它們住在同一條緯度線上,于是它們約定各自朝西跳,直到碰面為止??墒撬鼈兂霭l(fā)之前忘記了一件很重要的事情,既沒有問清楚對(duì)方的特征,
     *  也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們覺得只要一直朝著某個(gè)方向跳下去,總能碰到對(duì)方的。但是除非這兩只青蛙在同一時(shí)間跳到同一點(diǎn)上,不然是永遠(yuǎn)都不可能碰面的。為了幫助這兩只樂觀的青蛙,你被要求寫一個(gè)程序來判斷這兩只青蛙是否能夠碰面,會(huì)在什么時(shí)候碰面。
     *  我們把這兩只青蛙分別叫做青蛙A和青蛙B,并且規(guī)定緯度線上東經(jīng)0度處為原點(diǎn),由東往西為正方向,單位長(zhǎng)度1米,這樣我們就得到了一條首尾相接的數(shù)軸。設(shè)青蛙A的出發(fā)點(diǎn)坐標(biāo)是x,青蛙B的出發(fā)點(diǎn)坐標(biāo)是y。青蛙A一次能跳m米,青蛙B一次能跳n米,兩只青蛙跳一次所花費(fèi)的時(shí)間相同。
     *  緯度線總長(zhǎng)L米。現(xiàn)在要你求出它們跳了幾次以后才會(huì)碰面。
    * 
     *  輸入只包括一行5個(gè)整數(shù)x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
     * 
     *  輸出碰面所需要的跳躍次數(shù),如果永遠(yuǎn)不可能碰面則輸出一行"Impossible" 
     * Sample Input: 
     * 1 2 3 4 5 
     * Sample Output:
     * 4
     * 
     */
    public static long extGCD(long a, long b, long x, long y) {
        if(b == 0) {
            x = 1;
            y = 0;
            return a;
        }else {
            long d = extGCD(b, a % b, y, x);
            long temp = y;
            y = x - (a / b) * y;
            x = temp;
            return d;
        }
    }

    //分析:
    //設(shè)時(shí)間為t,青蛙A在t時(shí)間后的位置為x + m * t,青蛙B在t時(shí)間后的位置y + n * t
    //因?yàn)榫S度線可視作為一個(gè)圈,則可推出他們相遇時(shí)候的公式:(x + (m * t)) % L = (y + (n * t)) % L
    //上式轉(zhuǎn)換為:(m - n) * t + k * L = y - x;(t、k為未知數(shù),t為次數(shù),k為圈數(shù))
    //滿足ax + by = c
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        long x = in.nextLong();
        long y = in.nextLong();
        long m = in.nextLong();
        long n = in.nextLong();
        long L = in.nextLong();
        long a = m - n;
        long b = L;
        long c = y - x;
        long d = extGCD(a, b, x, y);
        if(c % d != 0) {
            System.out.println("Impossible");
        }else {
            x = x * c / d;
            long t = Math.abs(b / d);
            x = (x % t + t) % t;
            System.out.println(x);
        }
    }
}

2)素?cái)?shù)(也稱質(zhì)數(shù),質(zhì)數(shù)定義為在大于1的自然數(shù)中,除了1和它本身以外不再有其他因數(shù))

素?cái)?shù)篩選

static boolean[] is_prime = new boolean[100000];

public static void prime(int maxN) {
    Arrays.fill(is_prime, true);
    for(int i = 2; i * i < maxN; i++) {
        if(is_prime[i]) {
            for(int j = i * i; j < maxN; j += i) {
                is_prime[j] = false;
            }
        }
    }
}

3)歐拉函數(shù)(小于n且和n互質(zhì)(兩個(gè)數(shù)的最大公約數(shù)為1)的正整數(shù)(包括1)的個(gè)數(shù),如12的歐拉函數(shù)是φ(12)=4,有1,5,7,11)

單個(gè)數(shù)的歐拉函數(shù)

public static int euler(int n) {
    int res = n;
    for(int i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            res = res - res / i;
            while(n % i == 0) {
                n /= i;
            }
        }
    }
    if(n > 1) {
        res = res - res / n;
    }
    return res;
}

歐拉函數(shù)篩選

static final int MAX = 100000;
static int[] a = new int[MAX];

public static void euler_meter(){
    for(int i = 1; i < MAX; i++){
        a[i] = i;
    }
    for(int i = 2; i < MAX; i++){
        if(a[i] == i){
            for(int j = i; j < MAX; j += i){
                a[j] = a[j] - a[j] / i;
            }
        }
    }
}

3)博弈論

簡(jiǎn)單博弈

/*
小明經(jīng)常玩 LOL 游戲上癮,一次他想挑戰(zhàn)K大師,不料K大師說:
“我們先來玩?zhèn)€空格填字母的游戲,要是你不能贏我,就再別玩LOL了”。
K大師在紙上畫了一行n個(gè)格子,要小明和他交替往其中填入字母。

并且:
1. 輪到某人填的時(shí)候,只能在某個(gè)空格中填入L或O
2. 誰先讓字母組成了“LOL”的字樣,誰獲勝。
3. 如果所有格子都填滿了,仍無法組成LOL,則平局。

小明試驗(yàn)了幾次都輸了,他很慚愧,希望你能用計(jì)算機(jī)幫他解開這個(gè)謎。
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class Main {
    
    static Map<String, Integer> map = new HashMap<>();//記憶話搜索,記錄已經(jīng)走過的字符串及勝負(fù)情況
    
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(in.readLine());
        for(int i = 0; i < n; i++) {
            String s = in.readLine();
            System.out.println(game(s));
        }
    }

    private static int game(String s) {
        map.clear();
        return f(s.toCharArray());
    }

    private static int f(char[] c) {
        String s = new String(c);
        if(map.get(s) != null) {
            return map.get(s);
        }
        if(s.contains("LOL")) {
            map.put(s, -1);
            return -1;
        }
        if(!s.contains("*")) {
            map.put(s, 0);
            return 0;
        }
        boolean ping = false;
        for(int i = 0; i < c.length; i++) {
            if(c[i] == '*') {
                try {
                    c[i] = 'L';
                    {
                        int k = f(c);
                        if(k == -1) {
                            map.put(s, 1);
                            return 1;
                        }
                        if(k == 0) {
                            ping = true;
                        }
                    }
                    c[i] = 'O';
                    {
                        int k = f(c);
                        if(k == -1) {
                            map.put(s, 1);
                            return 1;
                        }
                        if(k == 0) {
                            ping = true;
                        }
                    }
                }finally {
                    c[i] = '*';
                }
            }
        }
        if(ping) {
            map.put(s, 0);
            return 0;
        }
        map.put(s, -1);
        return -1;
    }
}

NIM堆問題

/*
有3堆硬幣,分別是3,4,5
二人輪流取硬幣。
每人每次只能從某一堆上取任意數(shù)量。
不能棄權(quán)。
取到最后一枚硬幣的為贏家。

求先取硬幣一方有無必勝的招法。
*/
static void f(int[] a){
    int sum = 0;
    for(int i = 0; i < a.length; i++){
        sum ^= a[i];
    }
    if(sum == 0){
        System.out.println("輸了");
            return;
    }
    //打印必勝的方法
    for(int i=0; i<a.length; i++){
        int x = sum ^ a[i];
        if(x<a[i]) System.out.println(a[i] + " --> " + x);
    }
}

4)排列組合

全排列(0 ~ 9)

static int[] a = new int[10];
static boolean[] vis = new boolean[10];

public static void dfs(int step){
    if(step == 10){
        for(int i = 0; i < 10; i++){
            System.out.println(a[i] + " ");
        }
        return;
    }
    for(int i = 0; i < 10; i++){
        if(!vis[i]){
            vis[i] = true;
            a[step] = i;
            dfs(step + 1);
            vis[i] = false;
        }
    }
}

不重復(fù)全排列

static int[] a = {1, 1, 2};

public static void dfs(int k){
    if(k == a.length){
        for(int i = 0; i < a.length; i++){
            System.out.println(a[i] + " ");
        }
        return;
    }
    for(int i = k; i < a.length; i++){
        if(needSwap(k, i)){
            swap(i, k);
            dfs(step + 1);
            swap(i, k);
        }
    }
}

public static boolean needSwap(int from, int to) {
    for(int i = from; i < to; i++) {
        if(a[to] == a[i]) {
            return false;
        }
    }
    return true;
}

public static void swap(int x, int y) {
    int temp = a[x];
    a[x] = a[y];
    a[y] = temp;
}

不重復(fù)一般組合(例如,從4個(gè)中選3個(gè)所有組合)

static int[] a = {1, 1, 2, 4};

public static void select_combination(int k, int n){
    if(k == n){
        for(int i = 0; i < n; i++){
            System.out.println(a[i] + " ");
        }
        return;
    }
    for(int i = k; i < a.length; i++){
        if(needSwap(k, i)){
            swap(i, k);
            dfs(step + 1);
            swap(i, k);
        }
    }
}

public static boolean needSwap(int from, int to) {
    for(int i = from; i < to; i++) {
        if(a[to] == a[i]) {
            return false;
        }
    }
    return true;
}

public static void swap(int x, int y) {
    int temp = a[x];
    a[x] = a[y];
    a[y] = temp;
}

全組合(列出數(shù)列的全部子集):利用了狀態(tài)壓縮

public static void full_combination(int[] a) {
    int len = a.length;
    for(int i = 1; i < (1 << len); i++) {
        for(int j = 0; j < len; j++) {
            if((i & (1 << j)) > 0) {
                System.out.print(a[j] + " ");
            }
        }
        System.out.println();
    }
}

5)快速冪

a ^ b

public static long pow(int a, int b){
    int res = 1;
    while(b > 0){
        if((b & 1) == 1){
            res *= a;
        }
        b >>= 1;
        a *= a;
    }
    return res;
}

矩陣快速冪

static class Matrix{
    int n;
    int a[][] = new int[n][n];
    public Matrix(){}
    public Matrix(int n){
        this.n = n;
    }
}

public static Matrix matrix_pow(A, p, mod){
    Matrix B = unit(A.n);
    while(p > 0){
        if((p & 1) == 1){
            B = matrix_mult(B, A, mod);
        }
        p >>= 1;
        A = matrix_mult(A, A, mod);
    }
    return B;
}

public static Matrix unit(int n){
    Matrix B = new Matrix(n);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            if(i == j) {
                B.a[i][j] = 1;
            }else {
                B.a[i][j] = 0;
            }
        }
    }
    return B;
}

public static Matrix matrix_mult(Matrix A, Matrix B, int mod) {
    Matrix C = new Matrix(A.n, B.n);
    for(int i = 0; i < A.n; i++) {
        for(int j = 0; j < B.n; j++) {
            C.a[i][j] = 0;
            for(int k = 0; k < A.n; k++) {
                C.a[i][j] = C.a[i][j] + (A.a[i][k] * B.a[k][j] % mod);
            }
        }
    }
    return C;
}

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    int p = in.nextInt();
    int mod = in.nextInt();
    Matrix A = new Matrix(n);
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            A.a[i][j] = in.nextInt();
        }
    }
    Matrix res = matrix_pow(A, p, mod);
    for(int i = 0; i < res.n; i++) {
        for(int j = 0; j < res.n; j++) {
            System.out.print(res.a[i][j] + " ");
        }
        System.out.println();
    }
}

6)循環(huán)節(jié)長(zhǎng)度(a/b)

public static int f(int n, int m) {
    n = n % m;
    Vector<Integer> v = new Vector<>();
    while(true) {
        v.add(n);
        n *= 10;
        n = n % m;
        if (n == 0)
            return 0;
        if (v.indexOf(n) >= 0)
            return v.size() - v.indexOf(n);
    }
}

二、字符串(學(xué)的不多)

編輯距離

/*
編輯距離,?又稱Levenshtein距離(也叫做Edit Distance),是指兩個(gè)字串串之間,由一個(gè)轉(zhuǎn)成 另一個(gè)所需的少編輯操作次數(shù)。許可的編輯操作包括將?一個(gè)字符替換成另一個(gè)字符,插?一個(gè)字 符,刪除?個(gè)字符
*/

public static void main(String[] args){
    Scanner in = new Scanner(System.in);
    String s1 = in.nextLine();
    String s2 = in.nextLine();
    char[] c1 = s1.toCharArray();
    char[] c2 = s2.toCharArray();
    int len1 = c1.length;
    int len2 = c2.length;
    int[][] dp = new int[len1 + 1][len2 + 1];
    for(int i = 1; i <= len1; i++){
        dp[i][0] = i;
    }
    for(int i = 1; i <= len2; i++){
        dp[0][i] = i;
    }
    for(int i = 1; i <= len1; i++){
        for(int j = 1; j <= len2; j++){
            if(c[i - 1] == c[j - 1]){
                dp[i][j] = dp[i - 1][j - 1];
            }else{
                dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
            }
        }
    }
    System.out.println(dp[len1][len2]);
}

最長(zhǎng)公共子序列

/*
比如字符串1:BDCABA;字符串2:ABCBDAB 最長(zhǎng)公共子序列是:BCBA
*/
public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    String s = in.nextLine();
    char[] c1 = s.toCharArray();
    s = in.nextLine();
    char[] c2 = s.toCharArray();
    int len1 = c1.length;
    int len2 = c2.length;
    int dp[][] = new int[len1 + 1][len2 + 1];
    for(int i = 1; i <= len1; i++) {
        for(int j = 1; j <= len2; j++) {
            if(c1[i - 1] == c2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    System.out.println(dp[len1][len2]);
}

最長(zhǎng)上升子序列

/*
比如:2 5 3 4 1 7 6  其中最長(zhǎng)上升子序列是 2 3 4 7 
*/
public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    int[] a = new int[n];
    for(int i = 0; i < n; i++) {
        a[i] = in.nextInt();
    }
    int dp[] = new int[n];
    int ans = 1;
    for(int i = 0; i < n; i++) {
        dp[i] = 1;
        for(int j = i; j >= 0; j--) {
            if(dp[j] < dp[i]) {
                if(a[j] < a[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
        }
        ans = Math.max(dp[i], ans);
    }
    System.out.println(ans);
}

Karp-Rabin算法 (字符串匹配)

/**
比如:字符串1:abcaabcaabcbcabc 字符串2:abc 答案:4
*/
static int send = 31;

public static void karp_rabin(String s1, String s2){
    long hash_s2 = hash(s2);
    int len_s1 = s1.length();
    int len_s2 = s2.length();
    long[] hash_s1 = new long[len_s1 - len_s2 + 1];
    hash_s1[0] = hash(s1.subString(0, len_s2));
    int ans = 0;
    for(int i = len_s2; i < len_s1; i++){
        char newChar = s1.charAt(i);
        char oldChar = s1.charAt(i - len_s2);
        long v = (long) (hash_s1[i - len_s2] * send - oldChar * Math.pow(send, len_s2) + newChar);
        hash_s1[i - len_s2 + 1] = v;
    }
    for(int i = 0; i < hash_s1.length; i++) {
        if (hash_s1[i] == hash_s2) { // 當(dāng)j == len_s2的時(shí)候則說明第二個(gè)循環(huán)從頭掃到尾,即滿足題意。
            ans++;
            // 為了驗(yàn)證是否正確,進(jìn)行了下標(biāo)打?。ㄏ聵?biāo)0代表字符串的第一位)
            System.out.println("match:" + i);
            System.out.println(ans);
        }
    }
}

public static long hash(String s){
    int len = s.length();
    long hash = 0;
    for(int i = 0; i < len; i++){
        hash = send * hash + s.charAt(i);
    }
    return hash;
}

KMP算法(字符串匹配)

public static int[] solve_next(String s){
    int len = s.length();
    int[] next = new int[len];
    next[0] = -1;
    if(len == 1){
        return next;
    }
    next[1] = 0;
    int j = 1;
    int k = next[j];
    while(j < len - 1){
        if(k < 0 || s.charAt(j) == s.charAt(k)){
            next[++j] = ++k;
        }else{
            k = next[k];
        }
    }
    return next;
}

public static int kmp(String s1, String s2){
    int len_s1 = s1.length();
    int len_s2 = s2.length();
    int next[] = solve_next(s2);
    int i = 0;
    int j = 0;
    int count = 0;
    while(i < len_s1){
        if(j == -1 || s1.charAt(i) == s2.charAt(j)){
            i++;
            j++;
        }else{
            j = next[j];
        }
        if(j == len_s2){
            count++;
            i--;
            j = next[j - 1];
        }
    }
    return count;
}

三、背包問題

01背包

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int N = in.nextInt();
    int V = in.nextInt();
    int[] c = new int[N + 1];
    int[] w = new int[N + 1];
    for(int i = 1; i <= N; i++) {
        w[i] = in.nextInt();
        c[i] = in.nextInt();
    }
    int[] dp = new int[V + 1];
    for(int i = 1; i <= N; i++) {
        for(int j = V; j >= c[i]; j--) {
            dp[j] = Math.max(dp[j - c[i]] + w[i], dp[j]);
        }
    }
    System.out.println(dp[V]);
}

多重背包

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int N = in.nextInt();
    int V = in.nextInt();
    int[] c = new int[N + 1];
    int[] w = new int[N + 1];
    int[] n = new int[N + 1];
    for(int i = 1; i <= N; i++) {
        w[i] = in.nextInt();
        c[i] = in.nextInt();
        n[i] = in.nextInt();
    }
    int[] dp = new int[V + 1];
    for(int i = 1; i <= N; i++) {
        for(int j = V; j >= 0; j--) {
            for(int k = 0; k <= n[i]; k++){
                if(j >= k * c[i]){
                    dp[j] = Math.max(dp[j - c[i] * k] + k * w[i], dp[j]);
                }
            }
        }
    }
    System.out.println(dp[V]);
}

多重背包(二進(jìn)制優(yōu)化)

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int N = in.nextInt();
    int V = in.nextInt();
    int[] c = new int[N + 1];
    int[] w = new int[N + 1];
    int[] n = new int[N + 1];
    for(int i = 1; i <= N; i++) {
        w[i] = in.nextInt();
        c[i] = in.nextInt();
        n[i] = in.nextInt();
    }
    int[] dp = new int[V + 1];
    for(int i = 1; i <= N; i++) {
        int t = n[i];
        int k = 1;
        while(k < t){
            for(int j = V; j >= k * c[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - k * c[i]] + k * w[i]);
            }
            k *= 2;
            t -= k;
        }
        for(int j = V; j >= t * c[i]; j--) {
            dp[j] = Math.max(dp[j], dp[j - t * c[i]] + t * w[i]);
        }
    }
    System.out.println(dp[V]);
}

完全背包

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int N = in.nextInt();
    int V = in.nextInt();
    int[] c = new int[N + 1];
    int[] w = new int[N + 1];
    for(int i = 1; i <= N; i++) {
        w[i] = in.nextInt();
        c[i] = in.nextInt();
    }
    int[] dp = new int[V + 1];
    for(int i = 1; i <= N; i++) {
        for(int j = c[i]; j <= V; j++) {
            dp[j] = Math.max(dp[j - c[i]] + w[i], dp[j]);
        }
    }
    System.out.println(dp[V]);
}

混合背包

/*
題目鏈接:https://www.acwing.com/problem/content/7/
*/
import java.util.Scanner;

public class 背包問題_混合背包問題 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int V = in.nextInt();
        int[] v = new int[N + 1];
        int[] w = new int[N + 1];
        int[] s = new int[N + 1];
        for(int i = 1; i <= N; i++) {
            v[i] = in.nextInt();
            w[i] = in.nextInt();
            s[i] = in.nextInt();
        }
        int[] dp = new int[V + 1];
        for(int i = 1; i <= N; i++) {
            if(s[i] == -1) {
                for(int j = V; j >= v[i]; j--) {
                    dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
                }
            }else if(s[i] == 0) {
                for(int j = v[i]; j <= V; j++) {
                    dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
                }
            }else {
                int k = 1;
                int t = s[i];
                while(k < t) {
                    for(int j = V; j >= k * v[i]; j--) {
                        dp[j] = Math.max(dp[j], dp[j - k * v[i]] + k * w[i]);
                    }
                    t -= k;
                    k <<= 1;
                }
                for(int j = V; j >= t * v[i]; j--) {
                    dp[j] = Math.max(dp[j], dp[j - t * v[i]] + t * w[i]);
                }
            }
        }
        System.out.println(dp[V]);
    }
}

二維費(fèi)用背包問題

/*
題目鏈接:https://www.acwing.com/problem/content/8/
*/
import java.util.Scanner;

public class 背包問題_二維費(fèi)用背包問題 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int V = in.nextInt();
        int M = in.nextInt();
        int[] v = new int[N + 1];
        int[] m = new int[N + 1];
        int[] w = new int[N + 1];
        for(int i = 1; i <= N; i++) {
            v[i] = in.nextInt();
            m[i] = in.nextInt();
            w[i] = in.nextInt();
        }
        int[][] dp = new int[V + 1][M + 1];
        for(int i = 1; i <= N; i++) {
            for(int j = V; j >= v[i]; j--) {
                for(int k = M; k >= m[i]; k--) {
                    dp[j][k] = Math.max(dp[j][k], dp[j - v[i]][k - m[i]] + w[i]);
                }
            }
        }
        System.out.println(dp[V][M]);
    }
}

組合背包問題

/*
題目鏈接:https://www.acwing.com/problem/content/9/
*/
import java.util.Scanner;

public class 背包問題_分組背包問題 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int V = in.nextInt();
        int[] a = new int[N + 1];
        int[][] v = new int[N + 1][];
        int[][] w = new int[N + 1][];
        for(int i = 1; i <= N; i++) {
            a[i] = in.nextInt();
            v[i] = new int[105];
            w[i] = new int[105];
            for(int j = 1; j <= a[i]; j++) {
                v[i][j] = in.nextInt();
                w[i][j] = in.nextInt();
            }
        }
        int[] dp = new int[V + 1];
        for(int i = 1; i <= N; i++) {
            for(int j = V; j >= 0; j--) {
                for(int k = 1; k <= a[i]; k++) {
                    if(j >= v[i][k]){
                        dp[j] = Math.max(dp[j], dp[j - v[i][k]] + w[i][k]);
                    }
                }
            }
        }
        System.out.println(dp[V]);
    }
}

三、圖論

Dijkstra(鄰接矩陣形式)——求單源最短路(無負(fù)權(quán)邊)

import java.util.Arrays;
import java.util.Scanner;

public class 圖_最短路徑_dijkstra_鄰接矩陣 {
    
    private static int n, m;
    private static int[][] map;
    private static boolean[] vis;
    private static int[] dis;
    private static final int INF = 0x3f3f3f;
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        init();//初始化
        for(int i = 0; i < m; i++) {
            int a = in.nextInt();//起點(diǎn)
            int b = in.nextInt();//終點(diǎn)
            int c = in.nextInt();//權(quán)值
            insert(a, b, c);//無向圖
//          insert01(a, b, c);//有向圖
        }
        dijkstra(1);
        System.out.println(dis[n]);
    }

    private static void init() {
        map = new int[n + 1][n + 1];
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i == j) map[i][j] = 0;
                else map[i][j] = INF;
            }
        }
        vis = new boolean[n + 1];
        dis = new int[n + 1];
        Arrays.fill(dis, INF);
    }

    private static void dijkstra(int u) {
        for(int i = 1; i <= n; i++){
            dis[i] = map[u][i];
        }
        vis[i] = true;
        for(int i = 1; i <= n - 1; j++){
            int mind = INF;
            int minj = -1;
            for(int j = 1; j <= n; j++){
                if(!vis[j] && dis[j] < mind){
                    mind = dis[j];
                    minj = j;
                }
            }
            if(minj == -1) return;
            vis[minj] = true;
            for(int j = 1; j <= n; j++){
                if(map[minj][j] < INF){
                    if(dis[j] > dis[minj] + map[minj][j]){
                        dis[j] = dis[minj] + map[minj][j];
                    }
                }
            }
        }
    }

    //無向圖添加邊
    private static void insert(int a, int b, int c) {
        map[a][b] = c;
        map[b][a] = c;
    }
    
    //有向圖添加邊
    private static void insert(int a, int b, int c) {
        map[a][b] = c;
    }

}

Dijkstra(鄰接矩陣鏈表)——求單源最短路(無負(fù)權(quán)邊)

import java.util.Arrays;
import java.util.Scanner;

public class 圖_最短路徑_dijkstra_鄰接鏈表 {
    
    private static int n, m;
    private static boolean[] vis;
    private static int[] dis;
    private static final int INF = 0x3f3f3f;
    private static Edge[] e;
    private static int[] head;
    private static int size;
    
    static class Edge{
        int v;//終點(diǎn)
        int w;//權(quán)重
        int next;//下一條邊的id
        public Edge(){}
        public Edge(int v, int w, int next){
            this.v = v;
            this.w = w;
            this.next = next;
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        init();//初始化
        for(int i = 0; i < m; i++) {
            int a = in.nextInt();//起點(diǎn)
            int b = in.nextInt();//終點(diǎn)
            int c = in.nextInt();//權(quán)值
            insert(a, b, c);//無向圖
//          insert01(a, b, c);//有向圖
        }
        dijkstra(1);
        System.out.println(dis[n]);
    }

    private static void init() {
        e = new Edge[2 * m + 1];//無向圖
//      e = new Edge[m + 1];//有向圖
        vis = new boolean[n + 1];
        dis = new int[n + 1];
        Arrays.fill(dis, INF);
        head = new int[n + 1];
        Arrays.fill(head, -1);
    }

    private static void dijkstra(int u) {
        dis[u] = 0;
        for(int i = 1; i <= n; i++){
            int mind = INF;
            int minj = -1;
            for(int j = 1; j <= n; j++){
                if(!vis[j] && dis[j] < mind){
                    mind = dis[j];
                    minj = j;
                }
            }
            if(minj == -1){
                return;
            }
            vis[minj] = true;
            for(int j = head[minj]; j != -1; j = e[j].next){
                int v = e[j].v;
                int w = e[j].w;
                if(!vis[v] && dis[v] > dis[minj] + w){
                    dis[v] = dis[minj] + w;
                }
            }
        }
    }

    //無向圖添加邊
    private static void insert(int u, int v, int w) {
        e[size] = new Edge(v, w, head[u]);
        head[u] = size++;
        e[size] = new Edge(u, w, head[v]);
        head[v] = size++;
    }
    
    //有向圖添加邊
    private static void insert(int u, int v, int w) {
        e[size] = new Edge(b, c, head[a]);
        head[u] = size++;
    }

}

SPFA(鄰接鏈表)——單源最短路(有負(fù)權(quán)邊)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class 圖_最短路徑_spfa_鄰接鏈表 {
    
    private static int n, m, size;
    private static Edge[] e;
    private static int[] head;
    private static int[] dis;
    private static boolean[] vis;
    private static final int INF = 0x3f3f3f;
    private static int[] in;
    
    public static class Edge{
        int v;
        int w;
        int next;
        public Edge() {}
        public Edge(int v, int w, int next) {
            this.v = v;
            this.w = w;
            this.next = next;
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        init();
        for(int i = 0; i < m; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int c = in.nextInt();
            insert02(a, b, c);
        }
        if(spfa(1)) {
            System.out.println("有負(fù)環(huán)");
        }else {
            System.out.println(dis[n]);
        }
    }

    //加入負(fù)環(huán)判斷
    private static boolean spfa(int u) {
        vis[u] = true;
        dis[u] = 0;
        in[u]++;
        Queue<Integer> q = new LinkedList<>();
        q.add(u);
        while(!q.isEmpty()){
            int now = q.poll();
            vis[now] = false;
            for(int i = head[now]; i != -1; i = e[i].next){
                int v = e[i].v;
                int w = e[i].w;
                if(dis[v] > dis[u] + w){
                    dis[v] = dis[u] + w;
                    if(!vis[v]){
                        q.add(v);
                        vis[v] = true;
                        in[v]++;
                        if(in[v] > n) return true;
                    }
                }
            }
        }
        return false;
    }

    private static void init() {
        e = new Edge[2 * m + 1];
        head = new int[n + 1];
        Arrays.fill(head, -1);
        vis = new boolean[n + 1];
        dis = new int[n + 1];
        Arrays.fill(dis, INF);
        in = new int[n + 1];
    }

    private static void insert01(int u, int v, int w) {
        e[size] = new Edge(v, w, head[u]);
        head[u] = size++;
    }
    
    private static void insert02(int u, int v, int w) {
        insert01(u, v, w);
        insert01(v, u, w);
    }
}

floyd——多源最短路

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    int m = in.nextInt();
    int[][] map = new int[n + 1][n + 1];
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            if(i == j) map[i][j] = 0;
            else map[i][j] = 0x3f;
        }
    }
    for(int i = 0; i < m; i++) {
        int a = in.nextInt();
        int b = in.nextInt();
        int c = in.nextInt();
        map[a][b] = map[b][a] = c;
    }
    //floyd核心
    for(int k = 1; k <= n; k++){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                map[i][j] = Math.min(map[i][j], map[i][k] + map[k][j]);
            }
        }
    }
    System.out.println(map[1][n]);
}

圖的拓?fù)渑判?/h4>
public class 圖_拓?fù)渑判?{
    
    private static int n, m;
    private static Edge[] e;
    private static int[] indegree;
    private static int[] head;
    private static int size;
    
    public static class Edge{
        int v;
        int next;
        public Edge() {}
        public Edge(int v, int next) {
            this.v = v;
            this.next = next;
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        init();
        for(int i = 0; i < m; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            insert(a, b);
            indegree[b]++;
        }
        topo();
    }

    private static void topo() {
        Queue<Integer> q = new LinkedList<>();
        for(int i = 1; i <= n; i++) {
            if(indegree[i] == 0) {
                q.add(i);
            }
        }
        while(!q.isEmpty()) {
            int now = q.peek();
            System.out.println(now);
            q.poll();
            for(int i = head[now]; i != -1; i = e[i].next) {
                int v = e[i].v;
                indegree[v]--;
                if(indegree[v] == 0) {
                    q.add(v);
                }
            }
        }
    }

    private static void insert(int u, int v) {
        e[size] = new Edge(v, head[u]);
        head[u] = size++;
    }

    private static void init() {
        e = new Edge[m + 1];
        indegree = new int[n + 1];
        Arrays.fill(indegree, 0);
        head = new int[2 * m + 1];
        Arrays.fill(head, -1);
    }
}

最小生成樹——Kruskal

public class 最小生成樹 {
    
    static int n, m;
    static Edge[] e;
    static int[] pre;
    
    public static class Edge{
        int u;
        int v;
        int w;
        public Edge() {}
        public Edge(int u, int v, int w) {
            this.u = u;
            this.v = v;
            this.w = w;
        }
        @Override
        public String toString() {
            return "Edge [u=" + u + ", v=" + v + ", w=" + w + "]";
        }
    }
    
    public static int krusual(){
        init();
        Arrays.sort(e, new Comparator<Edge>() {
            public int compare(Edge o1, Edge o2) {
                return o1.w - o2.w;
            }
        });
        int count = 0;//記錄已生成的邊數(shù)
        int sum = 0;//記錄答案
        for(int i = 0; i < m; i++) {
            if(merge(e[i].u, e[i].v)) {
                count++;
                sum += e[i].w;
            }
            if(count == n - 1) {//滿足最小生成樹條件
                break;
            }
        }
        if(count < n - 1) {
            return -1;
        }else{
            return sum;
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        e = new Edge[m];
        for(int i = 0; i < m; i++) {
            e[i] = new Edge(in.nextInt(), in.nextInt(), in.nextInt());
        }
        int res = krusual();
        if(res == -1){
            System.out.println("不連通);
        }else{
            System.out.println(res);
        }
    }

    private static boolean merge(int u, int v) {
        int uu = find(u);
        int vv = find(v);
        if(uu != vv){
            pre[vv] == uu;
            return true;
        }
        return false;
    }

    private static int find(int u) {
        int r = u;
        while(r != pre[r]){
            r = pre[r];
        }
        return r;
    }

    //并查集初始
    private static void init() {
        pre = new int[n + 1];
        for(int i = 1; i <= n; i++) {
            pre[i] = i;
        }
    }
}

最小生成樹——Prim

import java.util.Arrays;
import java.util.Scanner;

public class 最小生成樹_Prim {
    
    static int n, m;
    static final int INF = 0x3f3f3f;
    static int[] head;
    static int size;
    static Edge[] e;
    static boolean[] vis;
    static int[] dis;
    
    static class Edge{
        int v;
        int w;
        int next;
        public Edge() {}
        public Edge(int v, int w, int next) {
            this.v = v;
            this.w = w;
            this.next = next;
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        init();
        int st = 0;
        for(int i = 0; i < m; i++) {
            int u = in.nextInt();
            int v = in.nextInt();
            int w = in.nextInt();
            insert(u, v, w);
            insert(v, u, w);
            st = u;
        }
        int res = prim(st);
        System.out.println(res);
    }

    private static int prim(int st) {
        int sum = 0;
        int count = 0;
        dis[st] = 0;
        for(int i = head[st]; i != -1; i = e[i].next) {
            int v = e[i].v;
            int w = e[i].w;
            if(dis[v] > w) {
                dis[v] = w;
            }
        }
        vis[st] = true;
        count++;
        while(count < n) {
            int mind = INF;
            int minj = -1;
            for(int i = 1; i <= n; i++) {
                if(!vis[i] && dis[i] < mind) {
                    mind = dis[i];
                    minj = i;
                }
            }
            vis[minj] = true;
            count++;
            sum += mind;
            for(int i = head[minj]; i != -1; i = e[i].next) {
                int v = e[i].v;
                int w = e[i].w;
                if(!vis[v] && dis[v] > w) {
                    dis[v] = w;
                }
            }
        }
        return sum;
    }

    private static void init() {
        head = new int[n + 1];
        Arrays.fill(head, -1);
        e = new Edge[m * 2 + 1];
        vis = new boolean[n + 1];
        dis = new int[n + 1];
        Arrays.fill(dis, INF);
    }

    private static void insert(int u, int v, int w) {
        e[size] = new Edge(v, w, head[u]);
        head[u] = size++;
    }
}

線段樹(多用于解決區(qū)間問題)

import java.util.Arrays;
import java.util.Scanner;

public class 線段樹_構(gòu)建 {
    
    private static final int MAX = 105;
    private static int[] a = new int[MAX];
    private static int[] minv = new int[MAX * 4];
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for(int i = 1; i <= n; i++) {
            a[i] = in.nextInt();
        }
        build_tree(1, 1, n);
        update_tree(1, 1, n, 5, 7);//更新線段樹中a數(shù)組下標(biāo)為5的值。
        query_tree(1, 1, n, 2, 5);//查詢2~5區(qū)間的最小值
    }


    //區(qū)間查詢
    private static int query_tree(int id, int l, int r, int x, int y) {
        if(x <= l && r <= y) {
            return minv[id];
        }
        int mid = (l + r) >> 1;
        int res = Integer.MAX_VALUE;
        if(x <= mid) {
            res = Math.min(res, query_tree(id << 1, l, mid, x, y));
        }
        if(y > mid) {
            res = Math.min(res, query_tree(id << 1 | 1, mid + 1, r, x, y));
        }
        return res;
    }

    //更新
    private static void update_tree(int id, int l, int r, int x, int v) {
        if(l == r) {
            minv[id] = v;
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) {
            update_tree(id << 1, l, mid, x, v);
        }else {
            update_tree(id << 1 | 1, mid + 1, r, x, v);
        }
        minv[id] = Math.min(minv[id << 1], minv[id << 1 | 1]);
    }

    //構(gòu)建線段樹
    private static void build_tree(int id, int l, int r) {
        if(l == r) {
            minv[id] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build_tree(id << 1, l, mid);
        build_tree(id << 1 | 1, mid + 1, r);
        minv[id] = Math.min(minv[id << 1], minv[id << 1 | 1]);
    }
}

四、二分

二分

private static int binary_search(Integer[] a, int k) {
    int l = 0;
    int r = a.length - 1;
    while(l <= r) {
        int mid = (r + l) >> 1;
        if(a[mid] == k) return mid;
        if(a[mid] < k) l = mid + 1;
        else r = mid - 1;
    }
    return -1;
}

最大值最小問題

public class 二分_最大值最小 {
    
    static int[] a = {2, 4, 6, 8, 10, 12, 14};
    
    public static void main(String[] args) {
        System.out.println(bsearch_maxMin(11));
    }

    private static int bsearch_maxMin(int x) {
        int l = 0;
        int r = a.length - 1;
        while(l < r) {
            int mid = (l + r) >> 1;
            if(x <= a[mid]) {
                r = mid;
            }else {
                l = mid + 1;
            }
        }
        return l;//返回5
    }
}

最小值最大問題

public class 二分_最小值最大 {
    
    static int[] a = {2, 4, 6, 8, 10, 12, 14};
    
    public static void main(String[] args) {
        System.out.println(bsearch_maxMin(3));
    }

    private static int bsearch_maxMin(int x) {
        int l = 0;
        int r = a.length - 1;
        while(l < r) {
            int mid = (l + r + 1) >> 1;
            if(x <= a[mid]) {
                r = mid - 1;
            }else {
                l = mid;
            }
        }
        return l;//返回4
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本章涉及知識(shí)點(diǎn)1、素?cái)?shù)的定義2、尋找素?cái)?shù)算法—短除法3、尋找素?cái)?shù)算法—篩選法4、互質(zhì)關(guān)系5、歐拉函數(shù)的證明6、歐拉...
    PrivateEye_zzy閱讀 4,729評(píng)論 0 6
  • ACM主要算法介紹 (以下是自己覺得比較好的算法學(xué)習(xí)的博客鏈接,自己做了部分順序和分類調(diào)整)(以下算法分類來自于:...
    Dask_Jhonson閱讀 3,965評(píng)論 0 0
  • ACM課程: lC/C++兩種語言 l高等數(shù)學(xué) l線性代數(shù) l數(shù)據(jù)結(jié)構(gòu) l離散數(shù)學(xué) l數(shù)據(jù)庫原理 l操作系統(tǒng)原理 ...
    5747閱讀 398評(píng)論 0 0
  • 數(shù)據(jù)結(jié)構(gòu)算法大全(用 PASCAL 描述) 1.數(shù)論算法 求兩數(shù)的最大公約數(shù) function gcd(a,b:i...
    心想事成_ae7e閱讀 581評(píng)論 0 0
  • 漸進(jìn)增強(qiáng) progressive enhancement: 針對(duì)低版本瀏覽器進(jìn)行構(gòu)建頁面,保證最基本的功能,然后再...
    Raalstalblack閱讀 131評(píng)論 0 1

友情鏈接更多精彩內(nèi)容