一、数论
1)GCD
GCD(求最大公约数)
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 数论_拓展GCD {
/**
* 题目描述:
* 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,
* 也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
* 我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。
* 纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
*
* 输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
*
* 输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"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;
}
}
//分析:
//设时间为t,青蛙A在t时间后的位置为x + m * t,青蛙B在t时间后的位置y + n * t
//因为维度线可视作为一个圈,则可推出他们相遇时候的公式:(x + (m * t)) % L = (y + (n * t)) % L
//上式转换为:(m - n) * t + k * L = y - x;(t、k为未知数,t为次数,k为圈数)
//满足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)素数(也称质数,质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数)
素数筛选
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)欧拉函数(小于n且和n互质(两个数的最大公约数为1)的正整数(包括1)的个数,如12的欧拉函数是φ(12)=4,有1,5,7,11)
单个数的欧拉函数
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;
}
欧拉函数筛选
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)博弈论
简单博弈
/*
小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。
K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。
小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
*/
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<>();//记忆话搜索,记录已经走过的字符串及胜负情况
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
二人轮流取硬币。
每人每次只能从某一堆上取任意数量。
不能弃权。
取到最后一枚硬币的为赢家。
求先取硬币一方有无必胜的招法。
*/
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;
}
}
}
不重复全排列
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;
}
不重复一般组合(例如,从4个中选3个所有组合)
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;
}
全组合(列出数列的全部子集):利用了状态压缩
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)循环节长度(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);
}
}
二、字符串(学的不多)
编辑距离
/*
编辑距离,⼜又称Levenshtein距离(也叫做Edit Distance),是指两个字串串之间,由一个转成 另一个所需的少编辑操作次数。许可的编辑操作包括将⼀一个字符替换成另一个字符,插⼊一个字 符,删除⼀个字符
*/
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]);
}
最长公共子序列
/*
比如字符串1:BDCABA;字符串2:ABCBDAB 最长公共子序列是: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]);
}
最长上升子序列
/*
比如:2 5 3 4 1 7 6 其中最长上升子序列是 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) { // 当j == len_s2的时候则说明第二个循环从头扫到尾,即满足题意。
ans++;
// 为了验证是否正确,进行了下标打印(下标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]);
}
多重背包(二进制优化)
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]);
}
}
二维费用背包问题
/*
题目链接:https://www.acwing.com/problem/content/8/
*/
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 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(邻接矩阵形式)——求单源最短路(无负权边)
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();//起点
int b = in.nextInt();//终点
int c = in.nextInt();//权值
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(邻接矩阵链表)——求单源最短路(无负权边)
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;//终点
int w;//权重
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();//起点
int b = in.nextInt();//终点
int c = in.nextInt();//权值
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(邻接链表)——单源最短路(有负权边)
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("有负环");
}else {
System.out.println(dis[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]);
}
图的拓扑排序
public class 图_拓扑排序 {
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;//记录已生成的边数
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++;
}
}
线段树(多用于解决区间问题)
import java.util.Arrays;
import java.util.Scanner;
public class 线段树_构建 {
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数组下标为5的值。
query_tree(1, 1, n, 2, 5);//查询2~5区间的最小值
}
//区间查询
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]);
}
//构建线段树
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
}
}