✔ ★ 算法基础笔记(Acwing)(三)—— 搜索与图论(17道题)【java版本】

news2024/11/24 9:42:38

搜索与图论

  • 1. DFS
        • 1. 排列数字(3分钟)
        • 2. n-皇后问题
  • 2. BFS(队列)
        • 1. 走迷宫
            • 二刷总结(队列存储一个节点pair<int,int>)
            • 三刷总结 走过的点标记上距离(既可以记录距离,也可以判断是否走过)
        • ★ ★ 例题2. 八数码
            • 二刷总结
  • 3. 树与图的dfs
        • 1. 树的重心
          • 二刷总结
            • 1. 如何找根节点?用无向图遍历,则不需要根节点
            • 2. 把dfs 中需要算出来的写出来,就清晰怎么写了
  • 4. 树与图的bfs(最短路)
        • 1. 图中点的层次( 无权最短路 )
  • 5. 拓扑排序
        • 1. 有向图的拓扑排序 ✔12.24
            • 做题总结
  • 6. 朴素dijkstra算法
        • 1. Dijkstra求最短路 I(邻接矩阵)✔12.24
            • 二刷总结
  • 7. 堆优化版dijkstra
        • ★ 1. Dijkstra求最短路 II(邻接表)✔12.24
            • while(heap.size())
  • 8. Bellman-Ford算法(遍历 边)
        • 1. 有边数限制的最短路 ✔ 12.24
            • 做题总结
  • 9. spfa 算法( 往回走 )
        • 1. spfa求最短路 ✔12.24
        • 做题总结:
  • 10. spfa判断负权回路
      • 例题 spfa判断负环 ✔12.26
        • 刷题总结
  • 11. floyd算法( 两两之间最短距离 )
        • 1. Floyd求最短路 ✔12.26
          • 做题总结
  • 12. 朴素版prim算法
        • 1. Prim算法求最小生成树
            • 1. 有向无向
            • 2. 当t选出来,cnt才+d[t]
            • 做题总结
  • 13. Kruskal算法
        • 1. Kruskal算法求最小生成树( 利用并查集 )
            • 只需sum++ 就可以知道一共用了几个并查集
  • 14. 染色法判别二分图
        • 染色法判定二分图 ✔ 12.28
          • 算法思路 + 做题总结
  • 15. 匈牙利算法
        • 二分图的最大匹配 ✔12.29
            • 每次遍历的点 都重新定义确定的女朋友

1. DFS

1. 排列数字(3分钟)

每次遍历dfs参数是 遍历的坑位
原题链接

import java.util.*;
public class Main{
    static int N = 10,n;
    static int[] path = new int[N];
    static boolean[] st = new boolean[N];
    public static void main(String[] args){
        Scanner scan  = new Scanner(System.in);
        n = scan.nextInt();
        dfs(0);
    }
    public static void dfs(int u){
        if(u == n){
            for(int i = 0 ; i < n ; i ++ ){
                System.out.print(path[i] + " ");
            }
            System.out.println();
            return;
        }
        for(int i = 1 ; i <= n ; i ++ ){
            if(!st[i]){
                path[u] = i;
                st[i] = true;
                dfs(u + 1);
                st[i] = false;
                //path[u] = 0;
            }
        }
    }
}

2. n-皇后问题

原题链接

方法 1. 按行遍历(过程中有回溯、剪枝)

思想:

  1. 每次递归中,遍历一行的元素,如果可以放皇后,就递归到下一行,下一行中不行了,就返回来,回溯,
import java.util.*;

public class Main
{
    static Scanner in = new Scanner(System.in);
    static int N = 20;
    static boolean[] col = new boolean[N], dg = new boolean[N], udg = new boolean[N];
    static char[][] chs = new char[N][N];
    static int n = 0;

    static void dfs(int u)
    {
        if (u == n)
        {
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    System.out.print(chs[i][j]);
                }
                System.out.println();
            }
            System.out.println();
            return;
        }

        for (int i = 0; i < n; i++)
        {
            if (!col[i] && !dg[i - u + n] && !udg[i + u])
            {
                chs[u][i] = 'Q';
                col[i] = dg[i - u + n] = udg[i + u] = true;
                dfs(u + 1);
                col[i] = dg[i - u + n] = udg[i + u] = false;
                chs[u][i] = '.';
            }
        }

    }

    public static void main(String[] args)
    {
        n = in.nextInt();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) chs[i][j] = '.';
        dfs(0);
    }

}

方法2. 按每个元素遍历(没有减枝)

// 不同搜索顺序 时间复杂度不同  所以搜索顺序很重要!
#include <iostream>
using namespace std;
const int N = 20;

int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N]; 
// 因为是一个个搜索,所以加了row

// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
    // 处理超出边界的情况
    if (y == n) y = 0, x ++ ;

    if (x == n) { // x==n说明已经枚举完n^2个位置了
        if (s == n) { // s==n说明成功放上去了n个皇后
            for (int i = 0; i < n; i ++ ) puts(g[i]);
            puts("");
        }
        return;
    }
    
//和上面按行遍历的差别就是,这里没有循环

    // 分支1:放皇后
    if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
        g[x][y] = 'Q';
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
        dfs(x, y + 1, s + 1);
        row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
        g[x][y] = '.';
    }

    // 分支2:不放皇后
    dfs(x, y + 1, s);
}


int main() {
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            g[i][j] = '.';

    dfs(0, 0, 0);

    return 0;
}

2. BFS(队列)

1. 走迷宫

二刷总结(队列存储一个节点pair<int,int>)
三刷总结 走过的点标记上距离(既可以记录距离,也可以判断是否走过)
  1. bfs 需要队列
  2. ==走过的点标记上距离(既可以记录距离,也可以判断是否走过)==没走过的置为-1
  3. (队列存储一个节点pair<int,int>)

原题链接
原题链接

import java.io.BufferedReader;
import java.io.*;

public class Main {
    public static int n,m;
    public static int[][] gap = new int[110][110];
    public static int[][] dist = new int[110][110];
    public static PII[] q = new PII[110*110];
    public static int hh,tt;

    public static void main(String[] args) throws IOException {
        BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter wt = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] s = rd.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        for (int i = 0; i < n; i++) {
            String[] st = rd.readLine().split(" ");
            for (int j = 0 ; j < m ;j ++ ) {
                gap[i][j] = Integer.parseInt(st[j]);
                dist[i][j] = -1;
            }
        }
        System.out.println(bfs());
        wt.close();
    }

    public static int  bfs(){
        hh = 0 ; tt = -1; //队列的头节点=0,尾节点 = 0;
        dist[0][0] = 0; // 我们首先站在的是第一个点,所以值距离设置为0
        q[++tt] = new PII(0,0); //然后将第一个点下标存入q队列中
        //利用向量的方法进行让他上下左右判断是否能够前进
        int[] dx = {-1,0,1,0};//上(-1,0) 下(1,0)
        int[] dy = {0,1,0,-1};//左(0,-1) 右(0,1)
        while(hh <= tt){
            PII t = q[hh++]; //每一次将头结点拿出来
            for(int i = 0 ; i < 4 ; i ++ ){//然后进行下一步要往哪里走,这里可能有多重选择可走
                int x = t.first + dx[i]; //这里进行x轴向量判断
                int y = t.second + dy[i];//这里进行y轴向量的判断
                //如果x,y满足在地图中不会越界,然后地图上的点g是0(表示可以走),
                //然后这里是没走过的距离d是-1;
                if(x >= 0 && x < n && y >= 0 && y < m && gap[x][y] == 0 && dist[x][y] == -1){
                    //将现在可以走的点(x,y)加上上一个点计数距离的点加上一,就是现在走到的点的距离
                    dist[x][y] = dist[t.first][t.second] + 1;
                    q[++tt] = new PII(x,y);//然后将这一个可以走的点存入队列尾
                }
            }
        }
        return dist[n-1][m-1]; //最后返回的是地图走到尽头最后一个位置的位置统计的距离
    }
    static class  PII {
        int first;
        int second;
        public PII(int first,int second) {
            this.first = first;
            this.second = second;
        }
    }
}

★ ★ 例题2. 八数码

原题链接

二刷总结
  1. 字符串存储二维数组
  2. 每种情况对应一个移动距离,正好就用map
  3. 字符串有find函数,map有count函数
  4. map的count就可以判别 该位置是否走过
    补充一点就是,一种情况只能走过一次!不可能走走走地出现与之前一样的情况,这不就是白走了嘛
  5. 先swap才能接着判断
import java.util.*;
public class Main{
    public static void swap(char[] arr,int x,int y){
        char temp = arr[x];
        arr[x] = arr[y];
        arr[y] = temp;
    }
    public static int bfs(String start ,String end){
        Map<String,Integer> map = new HashMap<>();// 用来存储每种方式走过的距离
        Queue<String> q = new LinkedList<>();//队列,用来存储内容

        q.offer(start);//将初试元素插入到队列的尾部
        map.put(start,0);//将初始状态的值对应map中value值对应0;表示还没有进行前进;

        int[] dx = {-1,0,1,0},dy = {0,1,0,-1};//表示前进方向;上下左右
        //如果队列不是空的继续循环
        while(!q.isEmpty()){
            String t = q.poll();//将队头元素返回并抛出

            int k  = t.indexOf('x');//找到x再String中的下标
            int x = k / 3 ; int y = k % 3;//然后进行以为数组转化成二维的操作下标操作

            if(t.equals(end)) return map.get(t); //如果进行过程中跟结束end相同的就提前结束

            for(int i = 0 ; i < 4 ;  i ++ ){//这里进行四种方案
                int a = x + dx[i],b = y + dy[i]; 
                if(a >= 0 && a < 3 && b >= 0 && b < 3){ //如果这种情况没有超出边界
                    //将这种情况的字符串转化成字符数组,能够有下标进行交换
                    char[] arr = t.toCharArray(); 
                    //然后交换x跟没有超出边界的值进行交换,二维转成一维下标x*3+y;
                    swap(arr, k, a * 3 + b);
                    //然后将字符数组转化成字符串
                    String str = new String(arr);
                    if(map.get(str) == null){ //如果这种情况对应的value值是null,说明还没有走过
                        map.put(str,map.get(t) + 1);//然后将这种情况对应进行上一步的距离加上1
                        q.offer(str);//然后将新的情况插入到队尾中
                    }
                }
                //思路:
                //比如走到距离为2即第二步时候,上下左右四种情况都可行的情况下,将每一中情况都
                //插入到队列尾部,然后queue[] = {2[1],2[1],2[1],2[1],3[1],3[1],3[2],3[4]};
                //队列会执行从前面开始2执行完之后可能会有3种情况往队列尾插入,
                //然后这样依次每一层进行搜索遍历

                //因为步数小的都会先插入到队列中,队列原则"先进先出"原则,所以肯定会把所有的
                //第二步执行完之后才会执行前面第二步执行过程中产生的三步,然后一直执行到最后第n步
            }

        }
        return -1; //如果执行完之后没有结果,那么返回-1;

    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        String start = "";
        for(int i = 0 ; i < 9 ; i ++ ){
            String s = scan.next();
            start += s;
        }
        String end = "12345678x";
        System.out.println(bfs(start,end));
    }
}

3. 树与图的dfs

1. 树的重心

原题链接

二刷总结
1. 如何找根节点?用无向图遍历,则不需要根节点
2. 把dfs 中需要算出来的写出来,就清晰怎么写了
void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
  1. 遍历过的点标记一下,不再遍历,因为无向图可能往回遍历
import java.util.*;
public class Main{
    static int N = 100010,M = N * 2,idx,n;
    static int[] h = new int[N];
    static int[] e = new int[M];//存的是双倍,所以是M
    static int[] ne = new int[M];//存的是双倍,所以是M
    static boolean[] st = new boolean[N];
    static int ans = N; //一开始将最大值赋值成N,最大了
    /***
     * 邻接表,存储方法
     * 邻接表不用管执行顺序,只需要知道每个节点能够执行到每个多少个节点就行
     * 比如案例中4 3 , 4 6 ,头结点4插入两个节点3和6,所以执行到4就能够执行3和6,
     * 固定的,邻接表就是这样子的
     ***/
    public static void add(int a,int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    //返回的是当前子树的数量,比如1下面的所有数量包括自己就是9
    public static int dfs(int u){
        int res = 0;//连通块中的最大值这个其实就是ans,到时候跟ans比较大小,小的话就赋值给ans的
        st[u] = true;//将这个删除的点标记,下次不在遍历
        int sum = 1;//将删除的点也算上是初始值就是1;到时候有利于求n-sum;

        //单链表遍历
        for(int i = h[u];i != -1 ; i = ne[i]){
            int j = e[i];//然后将每一个的指向的点用变量表示出来
            if(!st[j]){ //然后如果是没用过,没被标记过的,就可以执行
                int s = dfs(j);//然后递归他的邻接表上面所有能够抵达的点
                //然后返回的数量是他所删除的点下面的连通块的大小
                res = Math.max(res,s); //然后和res比较一下大小,谁大谁就是最大连通块
                sum += s; //这里是将每递归一个点,就增加一个返回的s,就可以将这个值作为返回值成为最大连通块
            }
        }
        /***
         * 因为邻接表表中只是往下面执行,删除的点的上面的连通块可能是最大的连通块,
         * 所以需要用总数减去我们下面所统计出来的最大的连通块
         * 然后将最大的连通块的值赋值给res
         * **/
        res = Math.max(res,n-sum); 
        //然后将每个次的最大值进行比较,留下最小的最大值
        ans = Math.min(res,ans);
        return sum;
    }    
    public static void main(String[] ags){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        //这里是将每一个头节点都赋值成-1
        for(int i = 1 ; i < N ; i++ ){
            h[i] = -1;
        }
        //案例输入输出
        for(int i = 0 ; i < n - 1 ; i ++){
            int a = scan.nextInt();
            int b = scan.nextInt();
            //因为是无向边,所以就两个数同时指向对方
            add(a,b);
            add(b,a);
        }
        dfs(1);//从1开始
        //最后输出的是最小的最大值
        System.out.println(ans);
    }
}

4. 树与图的bfs(最短路)

1. 图中点的层次( 无权最短路 )

原题链接
原题链接

import java.util.Scanner;
public class Main{
    static int N = 100010,n,m,idx,hh,tt;
    static int[] h = new int[N],e = new int[N],ne = new int[N];
    static int[] d = new int[N],q = new int[N];
    //这个是单链表的模板
    public static void add(int a,int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static int bfs(){
        hh = 0 ; tt = -1;
        d[1] = 0; // 第一个点是距离为0
        q[++tt] = 1; //然后将第一个点加进去
        //如果队列不是空的
        while(hh <= tt){
            int t = q[hh++]; //取出队头

            //然后遍历一下单链表
            for(int i = h[t] ; i != -1 ; i = ne[i]){

                int s = e[i]; //然后这个点用一个变量表示
                if(d[s] == -1){ //如果这个点是没走过的
                    d[s] = d[t] + 1; //然后将这个点距离加上1
                    q[++tt] = s;//然后将第二步的点加入到队尾中
                }
            }
        }
        return d[n]; //最后返回1到n的最短距离d


    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        //这里需要将距离跟头结点都赋值成-1
        for(int i = 1 ; i < N ; i++){
            h[i] = -1;
            d[i] = -1; 
        }
        for(int i = 0 ; i < m ; i ++ ){
            int a = scan.nextInt();
            int b = scan.nextInt();
            add(a,b);
        }
        System.out.println(bfs());
    }
}

5. 拓扑排序

1. 有向图的拓扑排序 ✔12.24

做题总结
  1. 拓扑是一个宽搜
  2. 遍历顺序是 度为0(可能有多个为0的)
  3. 可以用q[] 表示队列,这样就用一个队列就可以存储拓扑的结果和 遍历的过程了(也就是拓扑排序的遍历过程,就是答案顺序)

原题链接

import java.util.*;
public class Main{
    static int N =  100010,n,m,hh,tt,idx;
    static int[] e = new int[N],ne = new int[N],h = new int[N];
    static int[] q = new int[N];
    static int[] d = new int[N];
    public static void add(int a,int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;

    }
    public static boolean bfs(){
        hh = 0 ; tt = -1;
        for(int i = 1 ; i <= n ; i ++ ){ 
            if(d[i] == 0){     //首先将所有入度为0的点全部插入q队列中
                q[++tt] = i;
            }
        }
        while(hh <= tt){
            int t = q[hh++]; //拿出队头
            for(int i = h[t] ; i != -1; i = ne[i]){ //遍历一下队列中所有的边
                int s = e[i]; //然后将这个边拿出来
                d[s] -- ; //将这个边的入度数减1
                if(d[s] == 0){
                    q[++tt] = s; //如果减完之后s的入度数为0;就将他插入队列中
                }       
            }
        }
        return tt == n - 1; //最后返回,如果队列中的tt等于n-1个数,说明就是正确的的
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        for(int i = 0 ; i < N ; i ++ ){
            h[i] = -1; 
        }
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            add(a,b);
            d[b] ++;
        }

        if(bfs()){
            //队列刚好队头删除的点就是我们的拓扑序列,因为我们只是将hh往后面移动,但是它具体前面的值还在,直接输出就行
            for(int i = 0 ; i < n; i ++ ){ 
                System.out.print(q[i] + " ");
            }
        }else{
            System.out.println("-1");
        }
    }
}
#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

const int N = 1e5+10;

bool st[N];
int e[N],ne[N],idx,h[N];
int b[N];//每个节点的入读

int n,k;  

queue<int> q,ans;

void bfs()
{
    while(q.size())
    {
        int f = q.front();
        q.pop();
        for(int i = h[f]; i != -1; i = ne[i])
        {
                b[e[i]]--;
                if(b[e[i]]==0)
                {
                    ans.push(e[i]);
                    q.push(e[i]);
                }
            
        }
        
    }
    
}

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int main()
{ 
    memset(h,-1,sizeof h);
    cin >> n >> k;
    for(int i = 1; i <= k; i++)
    {
        int a,bb;
        cin >> a >> bb;
        add(a,bb);
        b[bb]++;
    }
    
    for(int i = 1; i <= n; i++)
    {
        if(b[i]==0)
        {
            //cout << i << endl;
            q.push(i);
            ans.push(i);
        }
    }
    bfs();
        if(ans.size()!=n)
    {
        cout << -1;
        return 0;
    }
    //cout << ans.size() << endl;
    
    while(ans.size())
    {
        cout << ans.front() << ' ';
        ans.pop();
    }
    
    return 0;
}

6. 朴素dijkstra算法

在这里插入图片描述

1. Dijkstra求最短路 I(邻接矩阵)✔12.24

原题链接
刷题总结

  1. 稀疏矩阵 和 疏密矩阵(疏密矩阵 可以用 邻接矩阵存储方式)
  2. 邻接矩阵直接就可以存储 边距离了
  3. d存储到1节点的距离
二刷总结
  1. dijk就是两步 :1. 在dist里选出最小值 2.遍历dist更新
    如何选(如下)
int t = -1;
for (int j = 1; j <= n; j ++ )
    if (!st[j] && (t == -1 || dist[t] > dist[j]))
        t = j;

import java.util.*;
public class Main{
    static int N = 510,n,m, max = 0x3f3f3f3f;
    static int[][] g = new int[N][N];//存每个点之间的距离
    static int[] dist = new int[N];//存每个点到起点之间的距离
    static boolean[] st = new boolean[N];//存已经确定了最短距离的点
    public static int dijkstra(){
        Arrays.fill(dist,max);//将dist数组一开始赋值成较大的数
        dist[1] = 0; //首先第一个点是零

        //从0开始,遍历n次,一次可以确定一个最小值
        for(int i = 0 ; i < n ; i ++ ){ 
            int t = -1; //t这个变量,准备来说就是转折用的
            for(int j = 1 ; j <= n ; j ++ ){
                /***
                 * 因为数字是大于1的,所以从1开始遍历寻找每个数
                 * 如果s集合中没有这个数
                 * 并且t == -1,表示刚开始 或者 后面的数比我心找的数距离起点的距离短
                 * 然后将j 的值赋值给 t
                 ***/
                if(!st[j] && (t == -1 || dist[j] < dist[t])){
                    t = j; 
                }
            }

            st[t] = true;//表示这个数是已经找到了确定了最短距离的点

            //用已经确认的最短距离的点来更新后面的点
            //就是用1到t的距离加上t到j的距离来更新从1到j的长度
            for(int j = 1 ; j <= n ; j ++ ){
                //
                dist[j] = Math.min(dist[j],dist[t] + g[t][j]);
            }
        }
        //如果最后n的长度没有改变,输出-1,没有找到;否则输出最短路n
        if(dist[n] == max) return -1;
        else return dist[n];

    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        //将他们每个点一开始赋值成一个较大的值
        for(int i = 1 ; i <= n ; i ++ ){
            Arrays.fill(g[i],max);
        }
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            g[a][b] = Math.min(g[a][b],c);//这个因为可能存在重边,所以泽出最短的
        }
        int res = dijkstra();
        System.out.println(res);
    }
}

7. 堆优化版dijkstra

★ 1. Dijkstra求最短路 II(邻接表)✔12.24

原题链接

while(heap.size())
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.PriorityQueue;

public class Main{
    static int N = 100010;
    static int n;

    static int[] h = new int[N];
    static int[] e = new int[N];
    static int[] ne = new int[N];
    static int[] w = new int[N];
    static int idx = 0;
    static int[] dist = new int[N];// 存储1号点到每个点的最短距离
    static boolean[] st = new boolean[N];
    static int INF = 0x3f3f3f3f;//设置无穷大
    public static void add(int a,int b,int c)
    {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx ++;
    }

    // 求1号点到n号点的最短路,如果不存在则返回-1
    public static int dijkstra()
    {
        //维护当前未在st中标记过且离源点最近的点
        PriorityQueue<PIIs> queue = new PriorityQueue<PIIs>();
        Arrays.fill(dist, INF);
        dist[1] = 0;
        queue.add(new PIIs(0,1));
        while(!queue.isEmpty())
        {
            //1、找到当前未在s中出现过且离源点最近的点
            PIIs p = queue.poll();
            int t = p.getSecond();
            int distance = p.getFirst();
            if(st[t]) continue;
            //2、将该点进行标记
            st[t] = true;
            //3、用t更新其他点的距离
            for(int i = h[t];i != -1;i = ne[i])
            {
                int j = e[i];
                if(dist[j] > distance + w[i])
                {
                    dist[j] = distance + w[i];
                    queue.add(new PIIs(dist[j],j));
                }
            }

        }
        if(dist[n] == INF) return -1;
        return dist[n];
    }

    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] str1 = reader.readLine().split(" ");
        n = Integer.parseInt(str1[0]);
        int m = Integer.parseInt(str1[1]);
        Arrays.fill(h, -1);
        while(m -- > 0)
        {
            String[] str2 = reader.readLine().split(" ");
            int a = Integer.parseInt(str2[0]);
            int b = Integer.parseInt(str2[1]);
            int c = Integer.parseInt(str2[2]);
            add(a,b,c);
        }
        System.out.println(dijkstra());
    }
}

class PIIs implements Comparable<PIIs>{
    private int first;//距离值
    private int second;//点编号

    public int getFirst()
    {
        return this.first;
    }
    public int getSecond()
    {
        return this.second;
    }
    public PIIs(int first,int second)
    {
        this.first = first;
        this.second = second;
    }
    @Override
    public int compareTo(PIIs o) {
        // TODO 自动生成的方法存根
        return Integer.compare(first, o.first);
    }
}

8. Bellman-Ford算法(遍历 边)

1. 有边数限制的最短路 ✔ 12.24

原题链接

做题总结
  1. b到1的距离 = min(a到1的距离 + a 到 b的距离)
import java.io.*;
import java.util.*;
public class Main{
    static int N = 510,M = 10010,n,m,k,max = 0x3f3f3f3f;
    static int[] dist = new int[N];//从一号点到n号点的距离
    static Node[] edgs = new Node[M];//结构体
    static int[] back = new int[N];//备份数组
    public  static void bellman_ford(){
        Arrays.fill(dist,max);//初始化一开始全部都是max
        dist[1] = 0;//然后第一个点到距离是0


        for(int i = 0 ; i < k ; i++ ){ //因为不超过k条边,所以只需要遍历k次,就可以找出最短距离,反之则没有

            back = Arrays.copyOf(dist,n+1);//备份:因为是从1开始存到n,所以需要n+1

            for(int j = 0 ; j < m ; j ++ ){ //因为总共m条边,所以遍历m次

                Node edg = edgs[j]; //每一条边的结构体 
                int a = edg.a;     
                int b = edg.b;
                int c = edg.c;
                dist[b] = Math.min(dist[b],back[a] + c); //用上面的点来更新后面的点
            }
        }

        //这里为什么是max/2呢?
        //因为到不了最后的n点,然后存在负权边能够到达n,将n的值更新了之后,变得比max小,防止出现这种情况
        if(dist[n] > max / 2) System.out.println("impossible");
        else System.out.println(dist[n]);
    }
    public static void main(String[] args)throws IOException{
        BufferedReader re = new BufferedReader(new InputStreamReader(System.in));
        String[] str = re.readLine().split(" ");
        n = Integer.parseInt(str[0]);
        m = Integer.parseInt(str[1]);
        k = Integer.parseInt(str[2]);
        for(int i = 0 ; i < m ; i ++){
            String[] s = re.readLine().split(" ");
            int a = Integer.parseInt(s[0]);
            int b = Integer.parseInt(s[1]);
            int c = Integer.parseInt(s[2]);
            edgs[i] = new Node(a,b,c);
        }
        bellman_ford();
    }
}
//创建一个构造体类
class Node{
    int a,b,c;
    public Node(int a,int b,int c){
        this.a = a;
        this.b = b;
        this.c = c;
    }
}

9. spfa 算法( 往回走 )

1. spfa求最短路 ✔12.24

原题链接

做题总结:

  1. 和宽搜差不多,只是可能会 返回走(但距离值更新了,就把这个节点入队列再处理一次)
import java.util.*;
public class Main{
    static int N = 100010,n,m,hh,tt,idx,INF = 0x3f3f3f3f;
    static int[] h = new int[N],e = new int[N],ne = new int[N],w = new int[N];
    static int[] q = new int[N],dist = new int[N];
    static boolean[] st = new boolean[N];
    public static void add(int a,int b,int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static void spfa(){
        hh = 0 ; tt =-1;
        Arrays.fill(dist,INF); //将dist一开始全部赋值成0x3f3f3f3f
        dist[1] = 0; //然后一开始的点距离是0
        q[++tt] = 1; //然后将第一个点插入到队列中
        st[1] = true;//标记第一个队列中有这个点
        while(hh <= tt){
            int t = q[hh ++ ]; //然后将队头弹出
            st[t] = false; //这里就将这个点在队列中取消标记
            for(int i = h[t]; i != -1 ; i = ne[i]){  //遍历所有的点
                int j = e[i];
                //如果后面的数比前面的数加t-j之间的位权的和要大,就说明应该更新一下最短距离了
                if(dist[j] > dist[t] + w[i]){ 
                    dist[j] = dist[t] + w[i];
                    //然后判断一下是不是队列中有这个点
                    if(!st[j]){
                        //没有就将这个点插入队列
                        q[++tt] = j;
                        //标记对列中有这个点
                        st[j] = true;
                    }
                }
            }
        }
        //spfa只会更新所有能从起点走到的点,所以如果无解,那么起点就走不到终点,那么终点的距离就是0x3f3f3f3f。
        if(dist[n] == INF) System.out.println("impossible");
        else System.out.println(dist[n]);
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        Arrays.fill(h,-1);
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            add(a,b,c);
        }
        spfa();
    }
}

10. spfa判断负权回路

原题链接

  1. 什么是负环
    在这里插入图片描述
    图1中:2 到 3 到 4 到 2 路径长度为 -10
    图2中:2 到 3 到 4 到 2 路径长度为 10

图1才叫负环
图2不是负环

  1. 出现负环会怎么样
    但出现负环的时候,如果我们要去求1到n的最短路,那么过程中,一定会在这个负环中一直转圈,导致路程可以变为负无穷

  2. 怎么判断图中是否有负环?
    综上,我们就采取求最小路径的方式(但是本题不是求最短路),当我们求最短路径的过程中,发现有一段路径重复走,那么就说明一定出现了负环

问题来了:怎么判断某段路径在重复走
我们想,1到n号点 最多才可能走了n-1条边
如果我们发现 到某点时 已经走了 大于等于n条边,那么一定就是有负环了
由于我们不知道 1 到 x点最多可能有多少条边,但一定不会超过 n - 1 条边,所以我们就都用 大于等于n条边去判断

例题 spfa判断负环 ✔12.26

原题链接

import java.util.*;
public class Main{
    static int N = 2010,M = 10010,n,m,idx;
    static int[] h = new int[N],e = new int[M],ne = new int[M],w = new int[M];
    static int[] cnt = new int[N]; //存多少边
    static int[] dist = new int[N];//存点到起点的距离
    static boolean[] st =  new boolean[N];//判断队列中是不是有这个数
    public static void add(int a,int b,int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static boolean spfa(){
        Queue<Integer> queue = new LinkedList<>();
        //Arrays.fill(dist,0x3f3f3f3f);
        //可能起点到不了负环,所以将所有的点都加入到对列中去
        for(int i = 1 ; i <= n ; i++ ){
            queue.offer(i);
            st[i] = true;//然后标记所有的点
        }

        while(!queue.isEmpty()){
            int t = queue.poll(); //然后将拿出队头
            st[t] = false; //然后标记已经不在队列中
            for(int i = h[t] ; i != -1 ;  i= ne[i]){ //遍历所有的点
                int j = e[i];
                //如果j到起点的距离 > 上个点t到起点的距离 +  t到j的距离,那么就更新dist[j]
                if(dist[j] > dist[t] + w[i]){   
                    dist[j] =  dist[t] + w[i];
                    cnt[j] = cnt[t] + 1; // 每一个次更新就将边加上1

                    //如果边大于n点数,n个点最多只有n-1条边,如果>= n的话,就至少有一个点出现了两次,则说明出线负环
                    if(cnt[j] >= n) return true; 
                    //然后判断对列中有没有点j,有则插并标记,无则不插
                    if(!st[j]){
                        queue.offer(j);
                        st[j] = true;
                    }
                }
            }
        }
        return false;
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        Arrays.fill(h,-1);
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            add(a,b,c);
        }
        if(spfa()) System.out.println("Yes");
        else System.out.println("No");
    }
}

刷题总结

  1. e,ne,h,idx 用于存储边,所以数值应该与边一样多
  2. 把所有点都入队列,防止不是连通图
  3. dist里存储多少都可以,因为我们只需判断负权回路
  4. 当一个点所走的路径长度大于n,那么就一定有负边,因为最多就是n正常的话。
  5. 一定要有st数组,判断是否再走这个点

11. floyd算法( 两两之间最短距离 )

在这里插入图片描述

1. Floyd求最短路 ✔12.26

原题链接

做题总结
  1. 用二维数组存储更方便
  2. 读入存储的时候,读取最小值,并且到自身值为0
  3. Floyd
import java.util.*;
public class Main{
    static int N = 210,n,m,k,INF = 0x3f3f3f3f;
    static int[][] g = new int[N][N];

    /***floyd算法只需要三重循环就可以解决问题,hh《很简单》
    * g[i,j,k] = min(g[i,j,k-1],g[i,k,k-1]+g[k,j,k-1]);
    * 原状态是:f[i, j, k]表示从i走到j的路径上除了i, j以外不包含点k的所有路径的最短距离。
    * 那么f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]。
    * 因此在计算第k层的f[i, j]的时候必须先将第k - 1层的所有状态计算出来,所以需要把k放在最外层。
    * 
    * 这里其实就是将所有k的可能性已经·存好,等待你输入就OK了
    ***/
    public static void floyd(){
        for(int k = 1 ; k <= n ; k ++ ){
            for(int i = 1 ; i <= n ; i ++ ){
                for(int j = 1 ; j <= n ; j ++ ){
                    g[i][j] = Math.min(g[i][j],g[i][k] + g[k][j]);
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        k = scan.nextInt();
        for(int i = 1 ; i <= n ; i ++ ){
            for(int j = 1 ; j <= n ; j ++ ){
                if(i == j) g[i][j] = 0; //可能存在询问自身到自身的距离,所以需要存0
                else g[i][j] = INF; //然后其他都可以存成INF最大值
            }    
        }
        while(m -- > 0 ){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            g[a][b] = Math.min(g[a][b],c); //这里可能存在重边,取最小的边
        }

        floyd();

        while(k -- > 0){
            int x = scan.nextInt();
            int y = scan.nextInt(); 
            int t  = g[x][y]; 
            //这里可能最后到不了目标点,但是可能路径上面存在负权边,然后将目标点更新了,所以不是到底== INF
            if(t > INF / 2) System.out.println("impossible");
            else System.out.println(t);

        }
    }
}

12. 朴素版prim算法

1. Prim算法求最小生成树

1. 有向无向
2. 当t选出来,cnt才+d[t]

原题链接

做题总结

1. 和dijk算法差不多 只是 dist数组存储的是 到联通块的距离

import java.util.*;
import java.io.*;
public class Main{
    static int N = 510,M = 100010,INF = 0x3f3f3f3f;
    static int n, m;
    static int[][] g = new int[N][N];
    static int[] dist = new int[N];
    static boolean[] st = new boolean[N];

    public static int prim(){
        Arrays.fill(dist,INF);
        int res = 0;

        for (int i = 0 ; i < n ; i ++ ){
            int t = -1;
            for (int j = 1 ; j <= n ; j ++ )
                if (!st[j] && (t == -1 || dist[j] < dist[t]))
                    t = j;

            st[t] = true;

            if (i != 0 && dist[t] == INF)  return INF;
            if (i != 0) res += dist[t];

            for (int j = 1 ; j <= n ; j ++ )
                dist[j] = Math.min(dist[j],g[t][j]);
        }
        return res;
    }

    public static void main(String[] args)throws IOException{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = bf.readLine().split(" ");
        n = Integer.parseInt(s1[0]);
        m = Integer.parseInt(s1[1]);

        for (int i = 0 ; i < N ; i ++ ) Arrays.fill(g[i],INF);

        while (m -- > 0){
            String[] s2 = bf.readLine().split(" ");
            int a = Integer.parseInt(s2[0]);
            int b = Integer.parseInt(s2[1]);
            int c = Integer.parseInt(s2[2]);
            g[a][b] = g[b][a] = Math.min(g[a][b],c);
        }

        int t = prim();

        if (t == INF) System.out.println("impossible");
        else System.out.println(t);
    }
}

13. Kruskal算法

在这里插入图片描述

1. Kruskal算法求最小生成树( 利用并查集 )

只需sum++ 就可以知道一共用了几个并查集

原题链接
原题链接

在这里插入图片描述

import java.util.*;
public class Main{
    static int N = 200010,n,m,w,INF = 0x3f3f3f3f;
    static Edgs[] edgs = new Edgs[N];//创建一个结构体
    static int[] p = new int[N];//集合
    //并查集模板,所有的集合在过程中全部指向根节点
    public static int find(int x){ 
        if(p[x] != x) p[x] = find(p[x]);
        return  p[x];
    }
    public static void kruskal(){
        Arrays.sort(edgs,0,m); //将结构体中的权重数据从小到大排序好

        int res = 0;//所有权重之和
        int cnt = 0;//加入集合的边数之和
        //枚举所有的边
        for(int i = 0 ; i < m ; i ++ ){
            int a = edgs[i].a;
            int b = edgs[i].b;
            int w = edgs[i].w;
            //判断一下a和b是不是在同一个集合中,不在集合中执行以下操作
            a = find(a);b = find(b);
            if(a != b){
                p[a] = b; //将两个集合合并
                res += w;//res增加权重
                cnt ++;//边数加1
            }
        }
        //因为有n个点,所以有n-1条边,所以如果小于n-1就是存在不连通的边,所以输出impossible,否则输出权重之和res
        if(cnt < n - 1) System.out.println("impossible");
        else System.out.println(res);
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        for(int i = 1 ; i<= n ; i ++ ) p[i] = i;
        for(int i = 0 ; i < m ; i ++ ){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int w = scan.nextInt();
            edgs[i] = new Edgs(a,b,w);
        }
        kruskal();
    }
}
class Edgs implements Comparable<Edgs>{
    int a,b,w;
    public Edgs(int a,int b,int w){
        this.a = a;
        this.b = b;
        this.w = w;
    }
    public int compareTo(Edgs o){
        return  Integer.compare(w,o.w);
    }
}

14. 染色法判别二分图

在这里插入图片描述

染色法判定二分图 ✔ 12.28

算法思路 + 做题总结

算法思路

  1. 通过dfs 一个染1 另一个染2(通过3-c)
  2. dfs需要有返回值。所以当 下一个返回来的是false,那么就返回false
    所以一个dfs中,通过判断有一个return false,并且还有一个根据下一个的return 再return false

做题总结

  1. 无向图 需要开辟 2倍

原题链接

原题链接

import java.util.*;
public class Main{
    static int N = 100010,M = N*2,n,m,idx;
    static int[] h = new int[N],e = new int[M],ne = new int[M];
    static int[] color = new int[N];
    public static void add(int a,int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static boolean dfs(int u,int c){
        color[u] = c; //首先将点u染色成c

        //然后遍历一下该点的所有边、
        for(int i = h[u]; i != -1; i = ne[i]){
            int j = e[i];
            //如果该点还没有染色
            if(color[j] == 0){
                //那就将该点进行染色,3-c是因为我们是将染色成1和2,如果是1,那就将对应的染成2,就用3来减法得出
                if(!dfs(j,3-c)) return false; //如果染完色之后返回false,那就说明里面含有奇数环,那就返回false
            }   
                //如果该点已经染过颜色吗,然后点的颜色跟我c的颜色是一样的,那就说明存在奇数环,返回false 
            else if(color[j] == c) return false; 
        }
        //最后如果很顺利的染完色,那就说明没有奇数环,那就返回true;
        return true;
    }
    public static void main(String[] args){
        Scanner scan =  new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        Arrays.fill(h,-1);
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            add(a,b);add(b,a);//因为是无向边,所以双方指向双方的两条边
        }
        boolean flag = true;
        for(int i = 1 ; i <= n ; i ++ ){
            //如果该点还没有染色
            if(color[i] == 0){
                //那就进行染色操作,第一个点可以自行定义1或者2,表示黑白
                if(!dfs(i,1)){
                    flag = false; //如果返回了false,说明有奇数环就将结束,输出No,否则输出Yes
                    break;
                }    
            }

        }
        if(flag) System.out.println("Yes");
        else System.out.println("No");
    }
}

15. 匈牙利算法

二分图的最大匹配 ✔12.29

每次遍历的点 都重新定义确定的女朋友

原题链接

import java.util.*;
public class Main{
    static int N = 510,M = 100010,n1,n2,m,idx;
    static int[] h = new int[N],e = new int[M],ne = new int[M];
    static int[] match = new int[M];
    static boolean[] st = new boolean[N];
    public static void add(int a,int b){
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static boolean find(int x){
        //每一次遍历一遍传进来的左边集合x对应的右边集合中的点
        for(int i = h[x]; i != -1; i = ne[i]){
            int  j = e[i];
            // 判断这个点是不是已经用过了,没用过继续
            if(!st[j]){  
                //这里st的作用大致就是递归时候起到判重的作用,因为下一位男生遍历时候一开始都会将st初始化为false
                //然后将这个点标记为有了,然后如果刚好标记之后这个位置的女生已经被上一个男生约定俗成了,
                //就递归看看这个男生是不是还有其他可以喜欢的女生,这个时候判重的作用就体现了,因为在这个过程中
                //st已经被true标记了,所以上一个男生重新遍历时候遍历到这个女生就知道要让给下一个男生,所以找到
                //自己的其他中意的女生,然后将自己与另外以为女生绑定,如果没有其他喜欢的女生,就返回flase,
                //然后下一个男生就是单生,或者看看自己还有没有其他喜欢的女生,以此类推,得出最完美结果!!!
                st[j] = true;
                if(match[j] == 0 || find(match[j])){
                    match[j] = x; //match是表示女生对应的男生是谁
                    return true;
                }
            }
        }
        return false;
    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);   
        n1 = scan.nextInt();
        n2 = scan.nextInt();
        m = scan.nextInt();
        Arrays.fill(h,-1);
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            add(a,b);
        }
        //统计最大匹配
        int res = 0;
        //遍历一下所有左半边集合的点
        for(int  i = 1 ; i <= n1 ; i ++ ){
            //每一次模拟都要将st数组清空,这个判断重复的点,match是物有所主了
            //st数组用来保证本次匹配过程中,右边集合中的每个点只被遍历一次,防止死循环。
            //match存的是右边集合中的每个点当前匹配的点是哪个,但就算某个点当前已经匹配了某个点,
            //也有可能被再次遍历,所以不能起到判重的作用。
            Arrays.fill(st,false);
            if(find(i)) res ++ ;
        }
        System.out.println(res);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1009919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

离线安装PX4日志分析工具Flight Review

使用Flight Review在线分析日志&#xff0c;有时会因为网络原因无法使用 使用离线安装的方式使用Flight Review&#xff0c;可以在无需网络的情况下使用Flight Review sudo apt-get install sqlite3 fftw3 libfftw3-devsudo apt-get install libatlas3-basegit clone --recur…

【Linux核心宝典】Linux 系统目录结构详解 - 01

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

Linux基础入门

一、操作系统安装方法 1、使用u盘安装 工具&#xff08;前提条件&#xff09;&#xff1a; <1>u盘 <2>镜像文件iso/msdn.itellyou.cn <3>把u盘做成PE&#xff1a;大白菜/老毛桃/winPE/软碟通/ultralSO 设置BIOS&#xff1a;通过u盘启动 安装系统&…

Vue项目中实现拖拽排序效果-demo

在Vue3中实现拖拽排序&#xff0c;可以借助一些浏览器自带的API&#xff0c;以及一些Vue3的特性&#xff1a; 使用<template>标签中的v-for指令渲染出一个列表&#xff0c;每个列表项绑定一个draggable属性&#xff0c;使其能够被拖拽。 <template><ul><…

一次I/O操作的过程

什么是IO呢&#xff1f; IO&#xff0c;英文全称是Input/Output&#xff0c;翻译过来就是输入/输出。平时我们听得挺多&#xff0c;就是什么磁盘IO&#xff0c;网络IO。那IO到底是什么呢&#xff1f;是不是有种懵懵懂懂的感觉呀&#xff0c;好像大概知道它是什么&#xff0c;又…

ARIMA模型

1、简介 ARIMA模型(Autoregressive Integrated Moving Average model)&#xff0c;差分整合移动平均自回归模型&#xff0c;又称整合移动平均自回归模型&#xff0c;时间序列预测分析方法之一。ARIMA(p,d,q)中&#xff0c;AR是"自回归"&#xff0c;p为自回归项数;MA…

二叉树题目:最大层内元素和

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;最大层内元素和 出处&#xff1a;1161. 最大层内元素和 难度 4 级 题目描述 要求 给定一个二叉树的根结点 ro…

zookeeper可视化工具ZooInspector用法

最近在做银行的项目&#xff0c;用到了thrift&#xff0c;rpc和zookeeper&#xff0c;所有应用都是注册到zookeeper上的&#xff0c;想知道哪些应用注册上了&#xff0c;就用到ZooInspector这个可视化的工具。 1&#xff0c;下载 链接&#xff1a;https://issues.apache.org/…

flex弹性盒模型与阿里图标的使用

华子目录 flex布局flex布局原理flex使用三要素 阿里图标&#xff08;字体&#xff09; flex布局 相关学习网站&#xff1a;http://c.biancheng.net/css3/flex.html 1.flex是当前最主流的布局方式&#xff1a;用它布局起来更方便&#xff0c;取代了浮动的作用。 2.浮动布局有缺…

BUG:阿里巴巴图标库引入链接后,icon有时候会不显示的话svg下载到本地使用

忽然icon图标就不显示&#xff0c;但是代码、icon链接地址都没有发生变化 解决办法&#xff1a;将icon图标下载到本地&#xff0c;记住前后引用本地的名字要保持一致

学习jQuery库的第一天

简介 什么是 jQuery &#xff1f; jQuery 是一个广泛使用的 JavaScript 库。它简化了网页开发中常见的许多任务&#xff0c;例如 HTML 文档遍历、操作 HTML 元素、处理事件、动画效果、Ajax 网络请求等。通过使用 jQuery&#xff0c;开发人员可以更加高效地编写跨浏览器兼容的…

如何制作一个成功的超市购物小程序

随着互联网的普及和移动支付的便捷性&#xff0c;越来越多的消费者选择在网上购物&#xff0c;这也促使越来越多的商家开始搭建自己的小程序商城。对于超市便利店来说&#xff0c;拥有一个便捷、易用的小程序商城能够吸引更多的消费者&#xff0c;提高销售效率。那么如何快速搭…

MyBatis初级

文章目录 一、mybatis1、概念2、JDBC缺点2.1、之前jdbc操作2.2 、原始jdbc操作的分析 3、mybatis的使用3.1、导入maven依赖3.2、新建表3.3、实体类3.4、编写mybatis的配置文件3.5、编写接口 和 映射文件3.6、编写测试类3.7、注意事项 4、代理方式开发5、mybatis和spring整合5.1…

数学实验-最佳分数近似值(Mathematica实现)

一、实验名称&#xff1a;最佳分数近似值 二、实验环境&#xff1a;Mathematica 10.3软件 三、实验目的&#xff1a;研究怎样用分数近似值去对给定的无理数作最佳逼近&#xff0c;“最佳”就是既要误差小&#xff0c;又要分母小。我们首先需要对“最佳”定出具体而明确的标准…

动态IP代理是什么?一文看懂动态代理IP

一、什么是动态IP代理&#xff1f; 动态IP代理是一种代理服务&#xff0c;而动态IP是由ISP动态分配给用户的IP地址&#xff0c;这些IP地址会周期性地更改。每次链接互联网时&#xff0c;用户会被分配一个新的IP地址&#xff0c;因而也称为”轮换IP”。 IP地址轮换是一个过程&…

Roreg复现

一、roreg复现 [github链接][参考] 1.1 报错1 Traceback (most recent call last): File "setup.py", line 52, in <module> import torch File "/home/w/anaconda3/envs/pty_roreg/lib/python3.7/site-packages/torch/__init__.py", line …

公司中一个好的管理者应该是什么样的?

一个好的管理者&#xff0c;不仅在公司中发挥着至关重要的作用&#xff0c;而且能够对组织的成功和员工的幸福产生深远的影响。那么&#xff0c;一个好的管理者应该具备哪些特质和技能呢&#xff1f;以下是我根据现有研究和经验总结出来的一些观点。 强大的领导力&#xff1a;…

【干货超全】国内外常见的Ai大模型汇总!!!

国内外常见的Ai大模型汇总: 点击文字即可跳转 1&#xff09;国内 讯飞星火大模型 https://xinghuo.xfyun.cn 百度文心一言 https://yiyan.baidu.com 阿里通义千问 https://tongyi.aliyun.com 华为盘古大模型 https://pangu.huaweicloud.com/ 清华智谱清言链接&#xff1…

卖课不挣钱,为什么还要卖?背后原因你绝对想不到

#职场经验谈# 大家好&#xff0c;这里是程序员晚枫&#xff0c;全网同名。 这几年一直在维护一个开源项目&#xff1a;python-office&#xff0c;GitHub和gitee都能搜索到。 我今晚算了一下&#xff0c;在维护这个开源项目的过程中&#xff0c;通过技术答疑、制作课程、发布广…

观测云接入 NewRelic .NET 探针

背景 部分客户系统采用的是.NET 4.5 部署研发的、基于 IIS 进行发布的 Web 项目&#xff0c;需要接入到观测云进行链路信息展示&#xff0c;ddtrace 和 otel 对于低版本.NET 支持力度有限。 环境信息 IIS 4.0.NET core 4.0、4.5、4.6Window Server 2012 R2 域名配置 准备一…