算法刷题日志

文章目录

      • 亲戚
    • 微博转发
      • [3502. 不同路径数](https://www.acwing.com/problem/content/description/3505/)
      • [3382. 整数拆分](https://www.acwing.com/problem/content/description/3385/)

亲戚

算法刷题日志_第1张图片

这题考察的是并查集,因为数据量过大所以这里我们使用快读快写,当数据的数量级为10^5时,用StreamTokenizer类差不多好像是要比Scanner快个300ms左右

import java.io.*;

public class Main{
    static int N = 20010;
    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 main(String[] args)throws IOException{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wt = new PrintWriter(new OutputStreamWriter(System.out));

        String[] s1 = bf.readLine().split(" ");
        int n = Integer.parseInt(s1[0]);
        int m = Integer.parseInt(s1[1]);
        for (int i = 1; i <= n; i ++) p[i] = i;

        while (m -- > 0){
            String[] s2 = bf.readLine().split(" "); //读入的时候用“ ”间隔
            int a = Integer.parseInt(s2[0]);
            int b = Integer.parseInt(s2[1]);
            if (find(a) != find(b)) p[find(a)] = find(b);//让这两个节点成为亲戚
        }

        int q = Integer.parseInt(bf.readLine());
        while (q -- > 0){
            String[] s3 = bf.readLine().split(" ");
            int a = Integer.parseInt(s3[0]);
            int b = Integer.parseInt(s3[1]);
            if (find(a) == find(b)) wt.println("Yes");
            else wt.println("No");
        }
        wt.flush();
    }
}

微博转发

算法刷题日志_第2张图片

bfs寻找最短路,每一个点产生链接就是为一层,然后不断bfs,每一次入队刚好就可以遍历完一层,

import java.util.*;

public class Main {
    static int N = 10010, M = 100010;
    static int n, L, k, idx;
    static int[] h = new int[N], e = new int[M], ne = new int[M];
    static boolean[] st = new boolean[N];  //默认为false


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

    public static int bfs(int start) {
        //每次访问都是独立的  需要重新初始化
        Queue<Integer> q = new LinkedList<>();
        Arrays.fill(st, false);
        q.offer(start);
        st[start] = true;


        int res = 0;
        for (int i = 0; i < L; i++) {
            int sz = q.size();  //每一层的点数
            while (sz -- > 0){
                int t = q.poll();
                for (int j = h[t]; j != -1; j = ne[j]) {
                    int x = e[j];
                    if (!st[x]){
                        q.offer(x);
                        st[x] = true;
                        res ++;
                    }
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); L = sc.nextInt();

        Arrays.fill(h, -1);
        for (int i = 1; i <= n; i++) { 
            int cnt = sc.nextInt();
            while (cnt -- > 0){
                int x = sc.nextInt();
                add(x, i);
            }
        }
        k = sc.nextInt();
        while (k -- > 0){
            int x = sc.nextInt();
            System.out.println(bfs(x));
        }
    }

}

3502. 不同路径数

算法刷题日志_第3张图片

用dfs在每个点都进行上下左右四个方向都走一次(当然要注意是否合法)
因为可以重复走, 所以遍历整个地图计算所有的可能性并存取到set集合当中,最后输出set的size就是答案数之和。
integer.parseInt()将string类型转换为int类型

import java.io.*;
import java.util.HashSet;

public class Main {
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    static int n, m, k;
    static int[][] g = new int[6][6];
    static int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};
    static HashSet<Integer> set = new HashSet<>();  //用来存储遍历过的数

    public static void dfs(int x, int y, int last, int index) {
        if (index > k + 1) return;  //当长度超过k + 1则返回
        last = last * 10 + g[x][y];  //先先遍历的数在最高位
        for (int i = 0; i < 4; i ++) {
            int a = x + dx[i], b = y + dy[i];
            if (a > 0 && a <= n && b > 0 && b <= m) dfs(a, b, last, index + 1);

            String s = String.valueOf(last);  //排除掉往回遍历的数,即实际长度不满足k + 1的数
            if (index == k + 1 && s.length() == k + 1 && !set.contains(last)) set.add(last);
        }
    }

    public static void main(String[] args) throws IOException {
        String[] s1 = in.readLine().split(" ");
        n = Integer.parseInt(s1[0]); m = Integer.parseInt(s1[1]); k = Integer.parseInt(s1[2]);
        //初始化
        for (int i = 1; i <= n; i ++) {
            String[] s2 = in.readLine().split(" ");//将读取数据存到string数组之中
            for (int j = 1; j <= m; j ++)
                g[i][j] = Integer.parseInt(s2[j - 1]);
        }
        //遍历每个点
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= m; j ++)
                dfs(i, j, 0, 1);
        out.println(set.size());
        out.flush();
    }
}

3382. 整数拆分

算法刷题日志_第4张图片

import java.io.*;

public class Main {
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    static int N = 1000010, n, mod = (int)1e9;
    static int[][] f = new int[21][N]; //从前i个物品中选,价值恰好为j
    static int[] w = new int[21];  //一共有0,2^0 ~ 2^19 二十种选法

    public static void main(String[] args) throws Exception {
        //初始化
        for (int i = 1; i <= 20; i ++) w[i] = (int)Math.pow(2, i - 1);
        n = Integer.parseInt(in.readLine());
        for (int i = 0; i <= 20; i ++) f[i][0] = 1;  //什么都不选是一种选法

        for (int i = 1; i <= 20; i ++)
            for (int j = 1; j <= n; j ++){
            //不选2^i
                f[i][j] = (f[i][j] + f[i - 1][j]) % mod;
                if (j >= w[i])
                //必选2^i,所以就不用考虑2^i,直接减去然后计算其他组合的情况
           
                    f[i][j] = (f[i][j] + f[i][j - w[i]]) % mod;
            }
        out.println(f[20][n]);
        out.flush();
    }
}

你可能感兴趣的:(算法,java,数据结构)