From 12b85ce5cc5ce04867ab8f265d12f347b4e00ffb Mon Sep 17 00:00:00 2001 From: Departuers <2644631299@qq.com> Date: Tue, 18 Aug 2020 09:35:28 +0800 Subject: [PATCH] c --- ...\345\255\220\346\270\270\346\210\217.java" | 34 +++++ ...\351\243\237\347\211\251\351\223\276.java" | 3 +- ...\345\217\267\345\214\271\351\205\215.java" | 2 +- ...\346\256\265\345\272\217\345\210\227.java" | 27 ++++ ...\347\247\215\350\247\243\346\263\225.java" | 10 ++ ...\347\232\204\346\227\205\350\241\214.java" | 9 +- ACWing/src/graph/dijkstra.java | 2 +- ACWing/src/graph/floyd.java | 1 + ...\346\226\255\350\264\237\347\216\257.java" | 18 ++- ...\347\232\204\350\201\230\347\244\274.java" | 14 +- ...\344\274\230\344\271\230\350\275\246.java" | 2 +- ...\344\275\263\347\272\277\350\267\257.java" | 122 ++++++++++++++++ ...\344\270\216\350\210\252\350\267\257.java" | 97 ++++++++++++- .../\345\214\272\351\227\264.java" | 100 ++++++++++++++ ...56\345\210\206\347\272\246\346\235\237.md" | 57 ++++++++ ...\351\230\237\345\270\203\345\261\200.java" | 117 ++++++++++++++++ .../\347\263\226\346\236\234.java" | 130 ++++++++++++++++++ ...\346\224\266\351\223\266\345\221\230.java" | 10 ++ ...\345\261\200\345\237\237\347\275\221.java" | 2 +- ...\347\232\204\351\203\275\345\270\202.java" | 2 +- ...\346\216\245\346\240\274\347\202\271.java" | 2 +- ...\350\256\257\347\275\221\347\273\234.java" | 12 +- ...\347\232\204\345\274\200\345\247\213.java" | 2 +- ...\347\224\237\346\210\220\346\240\221.java" | 26 ++++ ...17\347\224\237\346\210\220\346\240\221.md" | 8 +- ...\345\245\266\350\277\220\350\276\223.java" | 114 +++++++++++++++ ...\346\263\274\346\260\264\350\212\202.java" | 8 +- ...36\351\200\232\345\210\206\351\207\217.md" | 15 ++ ...\350\260\267\350\264\237\347\216\257.java" | 20 ++- ...\345\215\225\350\257\215\347\216\257.java" | 92 +++++++++++++ .../\350\231\253\346\264\236.java" | 35 ++++- ...\345\205\211\345\245\266\347\211\233.java" | 114 +++++++++++++++ .../\350\264\237\347\216\257.md" | 10 ++ ...347\254\254k\344\270\252\346\225\260.java" | 58 ++++++++ .../\350\266\212\347\213\261.java" | 44 ++++++ ...\344\271\230\345\210\206\350\247\243.java" | 39 +++++- ...\347\212\266\346\225\260\347\273\204.java" | 2 +- ...21\347\212\266\346\225\260\347\273\204.md" | 14 ++ ...\351\227\264\344\277\256\346\224\271.java" | 8 +- ...\345\205\260\345\233\276\350\205\276.java" | 74 ++++++++++ ...\346\240\267\347\232\204\347\211\233.java" | 111 +++++++++++++++ ...\351\200\206\345\272\217\346\225\260.java" | 73 ++++++++++ ...\351\227\264\346\237\245\350\257\242.java" | 21 +++ ...\345\205\260\345\233\276\350\205\276.java" | 87 ------------ 44 files changed, 1615 insertions(+), 133 deletions(-) create mode 100644 "ACWing/src/UnionFind/\346\240\274\345\255\220\346\270\270\346\210\217.java" rename "ACWing/src/basic/UnionFind/\351\243\237\347\211\251\351\223\276.java" => "ACWing/src/UnionFind/\351\243\237\347\211\251\351\223\276.java" (90%) create mode 100644 "ACWing/src/dp/\346\225\260\346\215\256\347\273\223\346\236\204\344\274\230\345\214\226dp/Cf958C3\345\210\206\346\256\265\345\272\217\345\210\227.java" create mode 100644 "ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\346\224\276\351\252\250\347\211\214\350\222\231\345\276\267\351\207\214\345\256\211\347\232\204\346\242\246\346\203\263\345\217\246\344\270\200\347\247\215\350\247\243\346\263\225.java" create mode 100644 "ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257\346\213\223\345\261\225/\351\200\211\346\213\251\346\234\200\344\275\263\347\272\277\350\267\257.java" create mode 100644 "ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\214\272\351\227\264.java" create mode 100644 "ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\267\256\345\210\206\347\272\246\346\235\237.md" create mode 100644 "ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\346\216\222\351\230\237\345\270\203\345\261\200.java" create mode 100644 "ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\347\263\226\346\236\234.java" create mode 100644 "ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\351\233\207\344\275\243\346\224\266\351\223\266\345\221\230.java" create mode 100644 "ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" create mode 100644 "ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\347\211\233\345\245\266\350\277\220\350\276\223.java" create mode 100644 "ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" create mode 100644 "ACWing/src/graph/\350\264\237\347\216\257/\345\215\225\350\257\215\347\216\257.java" create mode 100644 "ACWing/src/graph/\350\264\237\347\216\257/\350\247\202\345\205\211\345\245\266\347\211\233.java" create mode 100644 "ACWing/src/\346\225\260\345\255\246/\345\272\217\345\210\227\347\232\204\347\254\254k\344\270\252\346\225\260.java" create mode 100644 "ACWing/src/\346\225\260\345\255\246/\350\266\212\347\213\261.java" rename "ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204.java" => "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.java" (98%) create mode 100644 "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.md" rename "ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" => "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" (93%) create mode 100644 "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\245\274\345\205\260\345\233\276\350\205\276.java" create mode 100644 "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" create mode 100644 "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\351\200\206\345\272\217\346\225\260.java" create mode 100644 "ACWing/src/\347\272\277\346\256\265\346\240\221/\345\215\225\347\202\271\346\233\264\346\226\260\345\214\272\351\227\264\346\237\245\350\257\242.java" delete mode 100644 "ACWing/src/\347\272\277\346\256\265\346\240\221/\346\245\274\345\205\260\345\233\276\350\205\276.java" diff --git "a/ACWing/src/UnionFind/\346\240\274\345\255\220\346\270\270\346\210\217.java" "b/ACWing/src/UnionFind/\346\240\274\345\255\220\346\270\270\346\210\217.java" new file mode 100644 index 0000000..59c5bd5 --- /dev/null +++ "b/ACWing/src/UnionFind/\346\240\274\345\255\220\346\270\270\346\210\217.java" @@ -0,0 +1,34 @@ +package UnionFind; + +/** + * https://blog.csdn.net/weixin_44922845/article/details/104516620 + * Alice和Bob玩了一个古老的游戏:首先画一个 n×n 的点阵(下图 n=3 )。 + * 接着,他们两个轮流在相邻的点之间画上红边和蓝边: + * 直到围成一个封闭的圈(面积不必为 1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了,他们的游戏实在是太长了! + * 他们甚至在游戏中都不知道谁赢得了游戏。 + * 于是请你写一个程序,帮助他们计算他们是否结束了游戏? + * 输入格式 + * 输入数据第一行为两个整数 n 和 m。n表示点阵的大小,m 表示一共画了 m 条线。 + * 以后 m 行,每行首先有两个数字 (x,y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是 D,则是向下连一条边,如果是 R 就是向右连一条边。 + * 输入数据不会有重复的边且保证正确。 + * 输出格式 + * 输出一行:在第几步的时候结束。 + * 假如 m 步之后也没有结束,则输出一行“draw”。 + * 数据范围 + * 1≤n≤2001≤m≤240001≤n≤200 + * 1≤m≤24000 + * 输入样例 + * 3 5 + * 1 1 D + * 1 1 R + * 1 2 D + * 2 1 R + * 2 2 D + * 输出样例 + * 4 + */ +public class 格子游戏 { + public static void main(String[] args) { + + } +} diff --git "a/ACWing/src/basic/UnionFind/\351\243\237\347\211\251\351\223\276.java" "b/ACWing/src/UnionFind/\351\243\237\347\211\251\351\223\276.java" similarity index 90% rename from "ACWing/src/basic/UnionFind/\351\243\237\347\211\251\351\223\276.java" rename to "ACWing/src/UnionFind/\351\243\237\347\211\251\351\223\276.java" index c344062..075d076 100644 --- "a/ACWing/src/basic/UnionFind/\351\243\237\347\211\251\351\223\276.java" +++ "b/ACWing/src/UnionFind/\351\243\237\347\211\251\351\223\276.java" @@ -1,8 +1,9 @@ -package basic.UnionFind; +package UnionFind; import java.util.Scanner; /** + * https://blog.csdn.net/lisong_jerry/article/details/80029967?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-2&spm=1001.2101.3001.4242 * 带权并查集 * 精髓:只要两个元素在一个集合里面, * 通过它们与根节点的距离就能知道它们的相对关系 diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" index dfa8ce3..54dd9d9 100644 --- "a/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" @@ -30,7 +30,7 @@ public class 括号匹配 { if ((s[l] == '(' && s[r] == ')') || s[l] == '[' && s[r] == ']') { f[l][r] = f[l + 1][r - 1] + 2; }//查看头尾是否匹配 - + //如([])([])从中间分界线,那么它们依然可以匹配,符合要求 //枚举小区间,推出大区间最长序列 for (int k = l; k < r; k++) { f[l][r] = Math.max(f[l][k] + f[k + 1][r], f[l][r]); diff --git "a/ACWing/src/dp/\346\225\260\346\215\256\347\273\223\346\236\204\344\274\230\345\214\226dp/Cf958C3\345\210\206\346\256\265\345\272\217\345\210\227.java" "b/ACWing/src/dp/\346\225\260\346\215\256\347\273\223\346\236\204\344\274\230\345\214\226dp/Cf958C3\345\210\206\346\256\265\345\272\217\345\210\227.java" new file mode 100644 index 0000000..37432e4 --- /dev/null +++ "b/ACWing/src/dp/\346\225\260\346\215\256\347\273\223\346\236\204\344\274\230\345\214\226dp/Cf958C3\345\210\206\346\256\265\345\272\217\345\210\227.java" @@ -0,0 +1,27 @@ +package dp.数据结构优化dp; + +import java.util.Scanner; + +/** + * https://blog.csdn.net/Rose_max/article/details/82932210 + * 给你一个长度为n的序列,要求你把它分成K段 + * 每段的价值为这段的总权值%P + * 要求总价值最小 + * n<=500000 K<=100 P<=100 + * 4 3 10 4个数,分成3段,mod10最小 + * 3 4 7 2 + * out: + * 6 + * + */ +public class Cf958C3分段序列 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + k = sc.nextInt(); + m = sc.nextInt(); + + } + + static int n, k, m; +} diff --git "a/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\346\224\276\351\252\250\347\211\214\350\222\231\345\276\267\351\207\214\345\256\211\347\232\204\346\242\246\346\203\263\345\217\246\344\270\200\347\247\215\350\247\243\346\263\225.java" "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\346\224\276\351\252\250\347\211\214\350\222\231\345\276\267\351\207\214\345\256\211\347\232\204\346\242\246\346\203\263\345\217\246\344\270\200\347\247\215\350\247\243\346\263\225.java" new file mode 100644 index 0000000..c3ac21b --- /dev/null +++ "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\346\224\276\351\252\250\347\211\214\350\222\231\345\276\267\351\207\214\345\256\211\347\232\204\346\242\246\346\203\263\345\217\246\344\270\200\347\247\215\350\247\243\346\263\225.java" @@ -0,0 +1,10 @@ +package dp.状态压缩dp; + +public class 放骨牌蒙德里安的梦想另一种解法 { + public static void main(String[] args) { + + } + + static void dfs(int i, int now, int pre) { + } +} diff --git "a/ACWing/src/graph/Floyd/\347\211\233\347\232\204\346\227\205\350\241\214.java" "b/ACWing/src/graph/Floyd/\347\211\233\347\232\204\346\227\205\350\241\214.java" index ac8e7e1..6309306 100644 --- "a/ACWing/src/graph/Floyd/\347\211\233\347\232\204\346\227\205\350\241\214.java" +++ "b/ACWing/src/graph/Floyd/\347\211\233\347\232\204\346\227\205\350\241\214.java" @@ -6,6 +6,13 @@ package graph.Floyd; */ public class 牛的旅行 { public static void main(String[] args) { - + long i = 0; + long s = System.nanoTime(); + long t = 0; + for (i = 0; ; i++) { + if (i % 100000 == 0 && (System.nanoTime() - s) / 1e9 >= 0.98) + break; + } + System.out.println(i); } } diff --git a/ACWing/src/graph/dijkstra.java b/ACWing/src/graph/dijkstra.java index 37cd717..73d16be 100644 --- a/ACWing/src/graph/dijkstra.java +++ b/ACWing/src/graph/dijkstra.java @@ -55,7 +55,7 @@ public class dijkstra { c = nextInt(); add(a, b, c); } - Arrays.fill(dis, (1 << 31) - 1); + Arrays.fill(dis, (1 << 31)); dij(s); } diff --git a/ACWing/src/graph/floyd.java b/ACWing/src/graph/floyd.java index 11d64c0..6c5acb5 100644 --- a/ACWing/src/graph/floyd.java +++ b/ACWing/src/graph/floyd.java @@ -36,6 +36,7 @@ import java.util.Scanner; * 初始化为int/2即可 * 即使全是负权边,int/2-2*10^8,无穷-常数还是无穷 * 如何判别无穷呢,显然 int/4>2*10^8 + * */ public class floyd { public static void main(String[] args) { diff --git "a/ACWing/src/graph/spfa\345\210\244\346\226\255\350\264\237\347\216\257.java" "b/ACWing/src/graph/spfa\345\210\244\346\226\255\350\264\237\347\216\257.java" index 9aa930c..48549cf 100644 --- "a/ACWing/src/graph/spfa\345\210\244\346\226\255\350\264\237\347\216\257.java" +++ "b/ACWing/src/graph/spfa\345\210\244\346\226\255\350\264\237\347\216\257.java" @@ -54,24 +54,22 @@ public class spfa判断负环 { // 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。 ArrayDeque q = new ArrayDeque(); for (int i = 1; i <= n; i++) { - q.add(i); - vis[i] = true; + q.add(i);//假设超级源点连接每个点权值都为0 + st[i] = true; } int t = 0, x; while (!q.isEmpty()) { x = q.poll(); - vis[x] = false; + st[x] = false; for (int i = he[x]; i != 0; i = ne[i]) { t = e[i]; if (dis[t] > dis[x] + w[i]) { - dis[t] = dis[x] + w[i]; count[t] = count[x] + 1; + dis[t] = dis[x] + w[i]; if (count[t] >= n) return true; - if (!vis[t]) { - if (!q.isEmpty() && dis[t] < dis[q.peekFirst()]) { - q.addFirst(t); - } else q.add(t); - vis[t] = true; + if (!st[t]) { + q.add(t); + st[t] = true; } } } @@ -81,7 +79,7 @@ public class spfa判断负环 { static int[] count = new int[100005]; static int[] dis = new int[100005]; - static boolean[] vis = new boolean[100005]; + static boolean[] st = new boolean[100005]; static int[] he = new int[100005]; static int[] w = new int[200005]; static int[] ne = new int[200005]; diff --git "a/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\230\202\350\264\265\347\232\204\350\201\230\347\244\274.java" "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\230\202\350\264\265\347\232\204\350\201\230\347\244\274.java" index 16213ed..146b468 100644 --- "a/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\230\202\350\264\265\347\232\204\350\201\230\347\244\274.java" +++ "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\230\202\350\264\265\347\232\204\350\201\230\347\244\274.java" @@ -11,6 +11,7 @@ import java.util.Scanner; * 寻找最短路 * 等级问题的话,枚举等级区间 */ +@SuppressWarnings("all") public class 昂贵的聘礼 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); @@ -33,13 +34,24 @@ public class 昂贵的聘礼 { w[id][i] = Math.min(w[id][i], cost); } } + /** + * 因为最终要娶到公主,所以等级只能只能在level[1]也就是酋长的等级 + * level[1]-m ~ level[1]+m 这个区间内 + */ int res = Integer.MAX_VALUE / 2; - for (int i = level[1] - m; i <= level[1]; i++) { + for (int i = level[1] - m; i <= level[1]; i++) { res = Math.min(res, dijkstra(i, i + m)); } System.out.println(res); } + /** + * 枚举等级区间!来实现等级差距过大无法交易 + * + * @param down + * @param up + * @return + */ static int dijkstra(int down, int up) { Arrays.fill(dist, 0x3f3f3f3f); Arrays.fill(vis, false); diff --git "a/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\234\200\344\274\230\344\271\230\350\275\246.java" "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\234\200\344\274\230\344\271\230\350\275\246.java" index 17f8f3a..0f0ab01 100644 --- "a/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\234\200\344\274\230\344\271\230\350\275\246.java" +++ "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\346\234\200\344\274\230\344\271\230\350\275\246.java" @@ -21,6 +21,7 @@ import java.util.Scanner; * 2 * 建图,问题, * 2 3 4 5可以看做2-3 2-4 2-5 3-4 3-5 4-5 + * 抽象建图!想法很重要! * 显然:2可以直接到3,2也可以直接到4,2也可以直接到5 * 边权都为1可以使用bfs做 * 则显然求最小换乘次数,转换成求最短路径问题 @@ -49,7 +50,6 @@ public class 最优乘车 { static int[][] g = new int[510][510]; static int[] dist = new int[510]; - static int n, m; static void bfs() { diff --git "a/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257\346\213\223\345\261\225/\351\200\211\346\213\251\346\234\200\344\275\263\347\272\277\350\267\257.java" "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257\346\213\223\345\261\225/\351\200\211\346\213\251\346\234\200\344\275\263\347\272\277\350\267\257.java" new file mode 100644 index 0000000..a4565e2 --- /dev/null +++ "b/ACWing/src/graph/\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257\346\213\223\345\261\225/\351\200\211\346\213\251\346\234\200\344\275\263\347\272\277\350\267\257.java" @@ -0,0 +1,122 @@ +package graph.单源最短路拓展; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_30277239/article/details/106743915 + * 有一天,琪琪想乘坐公交车去拜访她的一位朋友。 + * 由于琪琪非常容易晕车,所以她想尽快到达朋友家。 + * 现在给定你一张城市交通路线图,上面包含城市的公交站台以及公交线路的具体分布。 + * 已知城市中共包含 n 个车站(编号1~n)以及 m 条公交线路。 + * 每条公交线路都是 单向的,从一个车站出发直接到达另一个车站,两个车站之间可能存在多条公交线路。 + * 琪琪的朋友住在 s 号车站附近。 + * 琪琪可以在任何车站选择换乘其它公共汽车。 + * 请找出琪琪到达她的朋友家(附近的公交车站)需要花费的最少时间。 + * 输入格式 + * 输入包含多组测试数据。 + * 每组测试数据第一行包含三个整数 n,m,s,分别表示车站数量,公交线路数量以及朋友家附近车站的编号。 + * 接下来 m 行,每x行包含三个整数 p,q,t,表示存在一条线路从车站 p 到达车站 q,用时为 t。 + * 接下来一行,包含一个整数 w,表示琪琪家附近共有 w 个车站,她可以在这 w 个车站中选择一个车站作为始发站。 + * 再一行,包含 w 个整数,表示琪琪家附近的 w 个车站的编号。 + * 输出格式 + * 每个测试数据输出一个整数作为结果,表示所需花费的最少时间。 + * 如果无法达到朋友家的车站,则输出 -1。 + * 每个结果占一行。 + * 数据范围 + * n≤1000,m≤20000, + * 1≤s≤n, + * 0 q = new ArrayDeque(); + q.add(0); + while (!q.isEmpty()) { + int t = q.poll(); + st[t] = false; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] > dis[t] + w[i]) { + dis[j] = dis[t] + w[i]; + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + if (dis[T] == inf) return -1; + else return dis[T]; + } + + static int inf = Integer.MAX_VALUE / 2; + + static void add(int a, int b, int c) { + e[cnt] = b; + w[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt++; + } + + static int n, m, T, N = 1100, M = 22010, cnt = 1; + static int[] e = new int[M]; + static int[] h = new int[N]; + static int[] w = new int[M]; + static int[] ne = new int[M]; + static int[] dis = new int[N]; + static boolean[] st = new boolean[N]; +} diff --git "a/ACWing/src/graph/\345\244\215\345\220\210\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\351\201\223\350\267\257\344\270\216\350\210\252\350\267\257.java" "b/ACWing/src/graph/\345\244\215\345\220\210\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\351\201\223\350\267\257\344\270\216\350\210\252\350\267\257.java" index 12b0dae..48081b7 100644 --- "a/ACWing/src/graph/\345\244\215\345\220\210\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\351\201\223\350\267\257\344\270\216\350\210\252\350\267\257.java" +++ "b/ACWing/src/graph/\345\244\215\345\220\210\345\215\225\346\272\220\346\234\200\347\237\255\350\267\257/\351\201\223\350\267\257\344\270\216\350\210\252\350\267\257.java" @@ -1,16 +1,111 @@ package graph.复合单源最短路; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Scanner; /** + * https://blog.csdn.net/qq_30277239/article/details/106629032 + * 农夫约翰正在一个新的销售区域对他的牛奶销售方案进行调查。 + * 他想把牛奶送到T个城镇,编号为1~T。 + * 这些城镇之间通过R条道路 (编号为1到R) 和P条航线 (编号为1到P) 连接。 + * 每条道路 i 或者航线 i 连接城镇Ai到Bi,花费为Ci。 + * 对于道路,0≤Ci≤10,000;然而航线的花费很神奇,花费Ci可能是负数(−10,000≤Ci≤10,000)。 + * 道路是双向的,可以从Ai到Bi,也可以从Bi到Ai,花费都是Ci。 + * 然而航线与之不同,只可以从Ai到Bi。 + * 事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策: + * 保证如果有一条航线可以从Ai到Bi,那么保证不可能通过一些道路和航线从Bi回到Ai。 + * 由于约翰的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。 + * 他想找到从发送中心城镇S把奶牛送到每个城镇的最便宜的方案。 + * 输入格式 + * 第一行包含四个整数T,R,P,S。 + * 接下来R行,每行包含三个整数(表示一个道路)Ai,Bi,Ci。 + * 接下来P行,每行包含三个整数(表示一条航线)Ai,Bi,Ci。 + * 输出格式 + * 第1..T行:第i行输出从S到达城镇i的最小花费,如果不存在,则输出“NO PATH”。 + * 数据范围 + * 1≤T≤25000, + * 1≤R,P≤50000, + * 1≤Ai,Bi,S≤T, + * 输入样例: + * 6 3 3 4 + * 1 2 5 + * 3 4 5 + * 5 6 10 + * 3 5 -100 + * 4 6 -100 + * 1 3 -10 + * 输出样例: + * NO PATH + * NO PATH + * 5 + * 0 + * -95 + * -100 * 如果边权非负使用Dijkstra算法 * spfa会被卡 * 把双向的非负块节点,用Dijkstra算法 - * 把一群节点,看做一个节点块 + * 把一群节点,看做一个节点块,按照拓扑序跑 */ public class 道路与航路 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); + for (int i = 0; i < block.length; i++) { + block[i] = new ArrayList(); + } + n = sc.nextInt(); + mr = sc.nextInt(); + mp = sc.nextInt(); + S = sc.nextInt(); + int a, b, c; + while (mr-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + add(a, b, c); + add(b, a, c); + } + for (int i = 1; i <= n; i++) { + if (id[i] == 0) { + dfs(i, ++bcnt); + } + } + while (mp-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + add(a, b, c); + } } + + static ArrayDeque q = new ArrayDeque(); + private static void dfs(int u, int bid) { + id[u] = bid; + block[bid].add(u); + for (int i = h[u]; i != 0; i = ne[i]) { + int j = e[i]; + if (id[j] == 0) + dfs(j, bid); + } + } + + private static void add(int a, int b, int c) { + e[cnt] = b; + w[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt++; + } + + static int n, mr, mp, S, N = 25010, M = 150010, cnt = 1, bcnt = 0; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] w = new int[M]; + static int[] ne = new int[M]; + static int[] id = new int[N]; + static int[] dis = new int[N]; + static boolean[] st = new boolean[N]; + static ArrayList block[] = new ArrayList[N]; + + } diff --git "a/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\214\272\351\227\264.java" "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\214\272\351\227\264.java" new file mode 100644 index 0000000..e1ba146 --- /dev/null +++ "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\214\272\351\227\264.java" @@ -0,0 +1,100 @@ +package graph.差分约束; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_44828887/article/details/107272314 + * 给定n个区间,[ai,bi]和n个整数Ci + * 你需要构造一个整数集合 Z, + * 使得∀i∈[1,n],Z 中满足ai≤x≤bi的整数 x 不少于 ci 个。 + * 求这样的整数集合 Z 最少包含多少个数。 + * 1≤n≤50000, + * 0≤ai,bi≤50000, + * 1≤ci≤bi−ai+1 + * 输入样例: + * 5 + * 3 7 3 + * 8 10 3 + * 6 8 1 + * 1 3 1 + * 10 11 1 + * 输出样例: + * 6 + * 该题必定有解,显然全放进去,一定满足要求 + * 思路: + * 先将不等式写出来 + * 将所有区间向右移一位,这样如果1-2有一条边 3-4有一条边, + * 我们应该让他可以处理为1-4区间, + * 所以相当于给的区间为左闭右闭的区间改为左闭右开的区间。 + * 初始的时候建立向右走1权值为0的边,向左走1权值为-1的边。 + * 跑最长路即可。 + * 列不等式: + * S0=0 + * Si表示1~i中被选出的数的个数 + * S5001的最小值,用最长路求解 + * Si>=S(i-1) 1<=i<=50001 + * Si-S(i-1)<=1 =>S(i-1)>=Si-1 + * [a,b]区间选c个,也就是Sb-S(a-1)>=c + * 不等关系要找全 + */ +public class 区间 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + for (int i = 1; i <= 50001; i++) { + add(i - 1, i, 0); + add(i, i - 1, -1); + } + int a, b, c; + while (n-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + a++; + b++; + add(a - 1, b, c); + } + spfa(); + System.out.println(dis[50001]); + } + + private static void spfa() { + q.add(0); + Arrays.fill(dis, -Integer.MAX_VALUE / 2); + st[0] = true; + dis[0] = 0; + while (!q.isEmpty()) { + int t = q.poll(); + st[t] = false; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] < dis[t] + w[i]) { + dis[j] = dis[t] + w[i]; + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + } + + + static int n, m, N = 50010, M = 150010, count = 1; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] ne = new int[M]; + static int[] w = new int[M]; + static int[] dis = new int[N]; + static boolean[] st = new boolean[N]; + static ArrayDeque q = new ArrayDeque(); + + static void add(int a, int b, int c) { + e[count] = b; + w[count] = c; + ne[count] = h[a]; + h[a] = count++; + } +} diff --git "a/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\267\256\345\210\206\347\272\246\346\235\237.md" "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\267\256\345\210\206\347\272\246\346\235\237.md" new file mode 100644 index 0000000..0e00d60 --- /dev/null +++ "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\345\267\256\345\210\206\347\272\246\346\235\237.md" @@ -0,0 +1,57 @@ +#差分约束 +###功能 +```` +1:求不等式的可行解, +源点满足,从源点出发,一定可以走到所有的边 +2:求最大值或最小值 +```` +###方法 +```` +形如 +Xi<=Xj+Ck +的一堆不等式,可以求出可行解 +其中i,j为自变量,c为常数 +{ +x1<=x2+1 +x2<=x3+2 +x3<=x1-2 +} +对于 +Xi<=Xj+Ck +我们类比三角不等式 +看做j->i连一条权值为c的边 +有dis[i]<=dis[j]+c +因为从j走到i,如果反之则不能走这条边 +```` +###步骤 +```` +1:Xi<=Xj+Ck +将不等式格式化,转化为j走到i长度为Ck的边 +不一定走到所有点,但一定要能走到所有边,限制的是边 +孤立的点也就是没有限制, +2:找到虚拟源点,使得虚拟源点可以到达所有的边 +3:从源点求单源最短路 + +如果存在负环,说明不等式组无解! +如:X1->X2->X1 权值之和小于0 +X2<=X1+C1 +X1<=X2+C2 +放缩X2<=X2+C2+C1 +显然矛盾 + +如果没有负环,则dis[i]就是可行解 +做一个对偶Xk>=Xi-Ck +i->连一条-Ck的边 +dis[j]>=dis[i]+Ck求最长路 + +如果是求的最小值,求最长路, +如果求的是最长值,应该求最短路 +应该有绝对关系,比如Xi>=0 +转化Xi<=c c为常数,这类的不等式 +建立超级源点为X0到i长度是0的边 +Xi<=C转化为Xi<=X0+C +构成不等式链对应路径,Xi<=Xj+C1<=Xk+C2+C1<=...<=X0+C1+C2... +Xi的最大值为一个所有上界的最小值等价于求0到i路径的最小值 + + + diff --git "a/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\346\216\222\351\230\237\345\270\203\345\261\200.java" "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\346\216\222\351\230\237\345\270\203\345\261\200.java" new file mode 100644 index 0000000..e08dcb9 --- /dev/null +++ "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\346\216\222\351\230\237\345\270\203\345\261\200.java" @@ -0,0 +1,117 @@ +package graph.差分约束; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/weixin_43872728/article/details/105941583 + * 当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。 + * 农夫约翰有 N 头奶牛,编号从 1 到 N,沿一条直线站着等候喂食。 + * 奶牛排在队伍中的顺序和它们的编号是相同的。 + * 因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。 + * 如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。 + * 一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数 L。 + * 另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数 D。 + * 给出 ML 条关于两头奶牛间有好感的描述,再给出 MD 条关于两头奶牛间存有反感的描述。 + * 你的工作是:如果不存在满足要求的方案,输出-1;如果 1 号奶牛和 N 号奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1 号奶牛和 N 号奶牛间可能的最大距离。 + * 输入格式 + * 第一行包含三个整数 N,ML,MD。 + * 接下来 ML 行,每行包含三个正整数 A,B,L,表示奶牛 A 和奶牛 B 至多相隔 L 的距离。 + * 再接下来 MD 行,每行包含三个正整数 A,B,D,表示奶牛 A 和奶牛 B 至少相隔 D 的距离。 + * 输出格式 + * 输出一个整数,如果不存在满足要求的方案,输出-1;如果 1 号奶牛和 N 号奶牛间的距离可以任意大,输出-2;否则,输出在满足所有要求的情况下,1 号奶牛和 N 号奶牛间可能的最大距离。 + * 数据范围 + * 2≤N≤1000, + * 1≤ML,MD≤104, + * 1≤L,D≤106 + * 思路 + * 不等式,并且使所有点联通,i<=i+1+0 + * 加入i+1向i的边 + */ +public class 排队布局 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + int m1 = sc.nextInt(); + int m2 = sc.nextInt(); + for (int i = 1; i < n; i++) { + add(i + 1, i, 0); + } + int a, b, c, t; + while (m1-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + if (b < a) { + t = b; + b = a; + a = t; + } + add(a, b, c); + } + while (m2-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + if (b < a) { + t = b; + b = a; + a = t; + } + add(b, a, -c); + } + if (!spfa(n)) System.out.println(-1); + else { + spfa(1); + if (dis[n] == Integer.MAX_VALUE / 2) System.out.println(-2); + else System.out.println(dis[n]); + } + } + + static boolean spfa(int size) { + Arrays.fill(dis, Integer.MAX_VALUE / 2); + Arrays.fill(st, false); + Arrays.fill(cnt, 0); + q.clear(); + for (int i = 1; i <= size; i++) { + dis[i] = 0; + q.add(i); + st[i] = true; + } + while (!q.isEmpty()) { + int t = q.poll(); + st[t] = false; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] > dis[t] + w[i]) { + dis[j] = dis[t] + w[i]; + cnt[j] = cnt[t] + 1; + if (cnt[j] >= n) return false; + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + return true; + } + + static int n, m, N = 1010, M = 21010, count = 1; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] ne = new int[M]; + static int[] w = new int[M]; + static int[] dis = new int[N]; + static int[] cnt = new int[N]; + static boolean[] st = new boolean[N]; + static ArrayDeque q = new ArrayDeque(); + + static void add(int a, int b, int c) { + e[count] = b; + w[count] = c; + ne[count] = h[a]; + h[a] = count++; + } +} diff --git "a/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\347\263\226\346\236\234.java" "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\347\263\226\346\236\234.java" new file mode 100644 index 0000000..232a287 --- /dev/null +++ "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\347\263\226\346\236\234.java" @@ -0,0 +1,130 @@ +package graph.差分约束; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_42279796/article/details/105072757 + * 幼儿园里有 N 个小朋友,老师现在想要给这些小朋友们分配糖果, + * 要求每个小朋友都要分到糖果. + * 但是小朋友们也有嫉妒心,总是会提出一些要求, + * 比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, + * 老师需要满足小朋友们的 K 个要求。 + * 幼儿园的糖果总是有限的,老师想知道他至少需要准备多少个糖果, + * 才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。 + * 输入格式 + * 输入的第一行是两个整数 N,K。 + * 接下来 K 行,表示分配糖果时需要满足的关系,每行 3 个数字 X,A,B。 + * 如果 X=1.表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多。 + * 如果 X=2,表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果。 + * 如果 X=3,表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果。 + * 如果 X=4,表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果。 + * 如果 X=5,表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果。 + * 小朋友编号从 1 到 N。 + * 输出格式 + * 输出一行,表示老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 −1。 + * 数据范围 + * 1≤N<105,1≤X≤5,1≤A,B≤N1≤N<10^5,1≤X≤5,1≤A,B≤N + * 输入样例: + * 5 7 + * 1 1 2 + * 2 3 2 + * 4 4 1 + * 3 4 5 + * 5 4 5 + * 2 3 5 + * 4 5 1 + * 输出样例: + * 11 + * 思路: + * 因为我们要求的是最小值且约束条件可转换为若干不等式,所以我们可以用差分约束来做,求最长路,不等式为大于号。 + * 将题目转换成一堆不等式 + * x=1=》A>=B&&B>=A + * x=2=》B>=A+1 + * x=3=》A>=B + * x=4=》A>=B+1 + * x=5=》B>=A + * 设一个超级原点x0,x0=0; + * 因为每个人至少有一个糖果,所以xi>=x0+1。 + * 本题可能出现无解的情况,即A>B+1&&B>A+1,所以需要判断是否存在环路,此时使用SPFA时应将queue改为stack,能提高速度。 + * 因为N较大,所以建图时不要使用vector(会超时),用前向星就行。 + */ +public class 糖果 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + int x, a, b; + while (m-- != 0) { + x = sc.nextInt(); + a = sc.nextInt(); + b = sc.nextInt(); + if (x == 1) { + add(b, a, 0); + add(a, b, 0); + } else if (x == 2) { + add(a, b, 1); + } else if (x == 3) { + add(b, a, 0); + } else if (x == 4) { + add(b, a, 1); + } else add(a, b, 0); + } + for (int i = 1; i <= n; i++) { + add(0, i, 1); + } + if (!spfa()) System.out.println("-1"); + else { + long res = 0; + for (int i = 1; i <= n; i++) { + res += dis[i]; + } + System.out.println(res); + } + } + + private static boolean spfa() {//求负环改成栈!!! + Arrays.fill(dis, finf); + dis[0] = 0; + q.clear(); + q.add(0); + st[0] = true; + while (!q.isEmpty()) { + int t = q.pollLast(); + st[t] = false; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] < dis[t] + w[i]) {//最长路! + dis[j] = dis[t] + w[i]; + cnt[j] = cnt[t] + 1; + if (cnt[j] >= n + 1) return false;//有负环 + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + return true; + } + + static int finf = Integer.MIN_VALUE / 2; + + static int n, m, N = 100010, M = 300010, count = 1; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] ne = new int[M]; + static int[] w = new int[M]; + static int[] dis = new int[N]; + static int[] cnt = new int[N]; + static boolean[] st = new boolean[N]; + static ArrayDeque q = new ArrayDeque(); + + static void add(int a, int b, int c) { + e[count] = b; + w[count] = c; + ne[count] = h[a]; + h[a] = count++; + } +} diff --git "a/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\351\233\207\344\275\243\346\224\266\351\223\266\345\221\230.java" "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\351\233\207\344\275\243\346\224\266\351\223\266\345\221\230.java" new file mode 100644 index 0000000..bc04fbd --- /dev/null +++ "b/ACWing/src/graph/\345\267\256\345\210\206\347\272\246\346\235\237/\351\233\207\344\275\243\346\224\266\351\223\266\345\221\230.java" @@ -0,0 +1,10 @@ +package graph.差分约束; + +/** + * + */ +public class 雇佣收银员 { + public static void main(String[] args) { + + } +} diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\345\261\200\345\237\237\347\275\221.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\345\261\200\345\237\237\347\275\221.java" index c5938ad..8b6b7b0 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\345\261\200\345\237\237\347\275\221.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\345\261\200\345\237\237\347\275\221.java" @@ -4,7 +4,7 @@ import java.util.PriorityQueue; import java.util.Scanner; /** - * https://blog.csdn.net/weixin_43872728/article/details/105852223 + * https://blog.csdn.net/qq_30277239/article/details/107898613 * 求最小生成森林 * 求每一个联通块的,最小生成树 * 使用Kruskal算法最好写,即使算法没有进行完,那么算法也是正确的 diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\347\271\201\345\277\231\347\232\204\351\203\275\345\270\202.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\347\271\201\345\277\231\347\232\204\351\203\275\345\270\202.java" index 6fd1809..69f9a69 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\347\271\201\345\277\231\347\232\204\351\203\275\345\270\202.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\347\271\201\345\277\231\347\232\204\351\203\275\345\270\202.java" @@ -4,7 +4,7 @@ import java.util.PriorityQueue; import java.util.Scanner; /** - * https://www.acwing.com/activity/content/code/content/308366/ + * https://blog.csdn.net/qq_30277239/article/details/107899568 * 求出无向图最小生成树中,最长边权的最小值 * 最小生成树的权值最大的边,对应Kruskal就是最后取到的那条边 */ diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\350\277\236\346\216\245\346\240\274\347\202\271.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\350\277\236\346\216\245\346\240\274\347\202\271.java" index 98d850c..42c5da0 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\350\277\236\346\216\245\346\240\274\347\202\271.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221/\350\277\236\346\216\245\346\240\274\347\202\271.java" @@ -3,7 +3,7 @@ package graph.最小生成树; import java.util.Scanner; /** - * https://blog.csdn.net/qq_42279796/article/details/103091446 + * https://blog.csdn.net/qq_30277239/article/details/107900698 * 依然Kruskal * 先选一些,再用Kruskal * 把二维坐标转化为一维坐标 diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\345\214\227\346\236\201\351\200\232\350\256\257\347\275\221\347\273\234.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\345\214\227\346\236\201\351\200\232\350\256\257\347\275\221\347\273\234.java" index cac2784..d73ca06 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\345\214\227\346\236\201\351\200\232\350\256\257\347\275\221\347\273\234.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\345\214\227\346\236\201\351\200\232\350\256\257\347\275\221\347\273\234.java" @@ -11,6 +11,13 @@ import java.util.Scanner; * 具有单调性,随着d的增加,k单调减少 * 最终Kruskal本质上在求连通性 * 当前循环完第i条边,求出由前i条边所构成的所有连通块 + * 输入样例: + * 3 2 + * 10 10 + * 10 0 + * 30 0 + * 输出样例: + * 10.00 */ public class 北极通讯网络 { public static void main(String[] args) { @@ -28,11 +35,12 @@ public class 北极通讯网络 { for (int j = 0; j < i; j++) { q.add(new node(i, j, getdist(list.get(i), list.get(j)))); } - } + }//预处理出所有的连接边, int cnt = n; double res = 0; + //枚举所有的, while (!q.isEmpty()) { - if (cnt <= k) break; + if (cnt <= k) break;//剩下的村庄可以通过卫星连接,不需要权值边,蛮优秀的想法 node p = q.poll(); int a = fin(p.x), b = fin(p.y); double w = p.w; diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\226\260\347\232\204\345\274\200\345\247\213.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\226\260\347\232\204\345\274\200\345\247\213.java" index 7ec4f8c..388e193 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\226\260\347\232\204\345\274\200\345\247\213.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\226\260\347\232\204\345\274\200\345\247\213.java" @@ -8,7 +8,7 @@ import java.util.Scanner; * 本来不是最小生成树问题 * 把在该节点新建一条边,看做向虚拟源点(0号点)连一条边 * 虚拟源点,是个非常重要的技巧,这样就变成了最小生成树问题 - * + * 图论问题,一定要先想到虚拟源点技巧 */ public class 新的开始 { public static void main(String[] args) { diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" new file mode 100644 index 0000000..df6180f --- /dev/null +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.java" @@ -0,0 +1,26 @@ +package graph.最小生成树拓展; + +/** + * https://blog.csdn.net/qq_41661919/article/details/86565228 + * Input + * 5 6 + * 1 2 1 + * 1 3 2 + * 2 4 3 + * 3 5 4 + * 3 4 3 + * 4 5 6 + * Output + * 11 + * 先求出最小生成树,并建树图,之后遍历所有非树边,用树上倍增 + * 求LCA的方法求出非树边两节点之间树边中的最大边和次大边,再将非 + * 树边权值与最大值比较,如果最大边<非树边(或者不等于,不等于一 + * 定<,要不然最小生成树就不是最小了)权值,用非树边替换最大边,否 + * 则(等于关系)用非树边替换次大边,最后从所有候选答案中选择最小值 + * 即次小生成树权值。 + */ +public class 次小生成树 { + public static void main(String[] args) { + + } +} diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.md" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.md" index a5d732b..921f3ca 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.md" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\346\254\241\345\260\217\347\224\237\346\210\220\346\240\221.md" @@ -3,7 +3,7 @@ 定义:给定一个带权的图,把图的所有生成树按权值从小到大排序 第二小的称为次小生成树 -则显然第一种定义,最小生成树和次小生成树的权值和相等 +则显然第一种定义,最小生成树和次小生成树的权值和可能相等 第二种定义:次小生成树严格大于最小生成树的权值和 次小生成树是权值和大于最小生成树的那个最小的那个生成树 @@ -13,5 +13,9 @@ 方法1:求最小生成树,再枚举删去最小生成树中的边求解 O(mlog m)+O(nm) 无法求严格次小生成树 -方法2:先求最小生成树,依次枚举非树边, +方法2:先求最小生成树,依次枚举非树边,可以求出严格最小生成树 然后将该边加入树,同时从树中去掉一条边,使得最终的图仍然是树,则一定可以求出次小生成树 +预处理,以任意节点为根,(BFS/DFS)枚举到任何点的最大边权O(n^2), 最终O(n^2+m+n^2+mlogn) +sum+w新-w树 +LCA预处理O(mlogn+m+n^2+mlogn) +存在一棵次小生成树和最小生成树相差一条边 diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\347\211\233\345\245\266\350\277\220\350\276\223.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\347\211\233\345\245\266\350\277\220\350\276\223.java" new file mode 100644 index 0000000..5f6ddbc --- /dev/null +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\347\211\233\345\245\266\350\277\220\350\276\223.java" @@ -0,0 +1,114 @@ +package graph.最小生成树拓展; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_41661919/article/details/86565228 + * https://blog.csdn.net/qq_44828887/article/details/107305636 + * 给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。 + * 设最小生成树的边权之和为sum,严格次小生成树就是指边权之和大于sum的生成树中最小的一个。 + * 输入格式 + * 第一行包含两个整数N和M。 + * 接下来M行,每行包含三个整数x,y,z,表示点x和点y之前存在一条边,边的权值为z。 + * 输出格式 + * 包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树) + * 数据范围 + * N≤105,M≤3∗105 + * 思路 + * lca次小生成树。倍增找树上路径最大边即可。 + */ +public class 牛奶运输 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + int a, b, w; + for (int i = 0; i < m; i++) { + a = sc.nextInt(); + b = sc.nextInt(); + w = sc.nextInt(); + edge.add(new node(a, b, w)); + } + Collections.sort(edge); + for (int i = 1; i <= n; i++) { + p[i] = i; + } + long sum = 0; + for (int i = 0; i < m; i++) { + a = find(edge.get(i).a); + b = find(edge.get(i).b); + w = edge.get(i).w; + if (a != b) { + p[a] = b; + sum += w; + add(a, b, w); + add(b, a, w); + edge.get(i).isShu = true; + } + } + for (int i = 1; i <= n; i++) { + dfs(i, -1, 0, dis[i]); + } + long res = (long) 1e18; + for (int i = 0; i < m; i++) { + if (!edge.get(i).isShu) { + a = edge.get(i).a; + b = edge.get(i).b; + w = edge.get(i).w; + if (w > dis[a][b]) { + res = Math.min(res, sum + w - dis[a][b]); + } + } + } + System.out.println(res); + } + + static void dfs(int u, int fa, int maxd, int[] d) { + d[u] = maxd; + for (int i = h[u]; i != 0; i = ne[i]) { + int j = e[i]; + if (j != fa) { + dfs(j, u, Math.max(maxd, w[i]), d); + } + } + } + + static void add(int a, int b, int c) { + e[cnt] = b; + w[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt++; + } + + static int find(int a) { + if (p[a] != a) return p[a] = find(p[a]); + return a; + } + + static class node implements Comparable { + int a, b, w; + boolean isShu; + + public node(int a, int b, int w) { + this.a = a; + this.b = b; + this.w = w; + } + + @Override + public int compareTo(node node) { + return w - node.w; + } + } + + static int n, m, N = 510, cnt = 1, M = 10010; + static ArrayList edge = new ArrayList(); + static int[] p = new int[N];//并查集 + static int[][] dis = new int[N][N]; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] w = new int[M]; + static int[] ne = new int[M]; +} diff --git "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\350\265\260\345\273\212\346\263\274\346\260\264\350\212\202.java" "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\350\265\260\345\273\212\346\263\274\346\260\264\350\212\202.java" index c5ba3b6..abad0ed 100644 --- "a/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\350\265\260\345\273\212\346\263\274\346\260\264\350\212\202.java" +++ "b/ACWing/src/graph/\346\234\200\345\260\217\347\224\237\346\210\220\346\240\221\346\213\223\345\261\225/\350\265\260\345\273\212\346\263\274\346\260\264\350\212\202.java" @@ -1,6 +1,7 @@ package graph.最小生成树拓展; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Scanner; @@ -9,6 +10,8 @@ import java.util.Scanner; * 给定一个N个节点的树, * 把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树 * 连接两个集合的新边, + * 把最小生成树,扩充,则新加的边必须严格大于最小生成树的边, + * 都取边权w+1最小的那个满足要求 */ public class 走廊泼水节 { public static void main(String[] args) { @@ -32,8 +35,9 @@ public class 走廊泼水节 { node c = q.get(i); int a = find(c.x), b = find(c.y); if (a != b) { - res += (size[a] * size[b] - 1) * (c.w + 1); - size[b] += size[a]; + res += (size[a] * size[b] - 1) * (c.w + 1);//新边都取w+1 + System.out.println(Arrays.toString(size)); + size[b] += size[a];//合并两个集合 par[a] = b; } } diff --git "a/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" new file mode 100644 index 0000000..de97dbd --- /dev/null +++ "b/ACWing/src/graph/\346\234\211\345\220\221\345\233\276\347\232\204\345\274\272\350\201\224\351\200\232\345\210\206\351\207\217/\345\274\272\350\277\236\351\200\232\345\210\206\351\207\217.md" @@ -0,0 +1,15 @@ + +``` +对于一个有向图,连通分量:对于分量中的任意两点u,v +必然可以从u走到v,且从v走到u + +强联通分量:极大联通分量 +有向图->缩点,有向无环图(DAG拓扑图) +缩点,将所有连通分量缩成一个点 + +按照dfs序来求 +分为四类:树枝边(x,y) +前向边(x,y) +后向边 +横叉边 +SCC强连通分量 diff --git "a/ACWing/src/graph/\346\264\233\350\260\267\350\264\237\347\216\257.java" "b/ACWing/src/graph/\346\264\233\350\260\267\350\264\237\347\216\257.java" index 286d04a..2f72250 100644 --- "a/ACWing/src/graph/\346\264\233\350\260\267\350\264\237\347\216\257.java" +++ "b/ACWing/src/graph/\346\264\233\350\260\267\350\264\237\347\216\257.java" @@ -77,11 +77,7 @@ public class 洛谷负环 { if (count[t] >= n) return true; if (!vis[t]) { vis[t] = true; - if (!q.isEmpty() && dis[t] < dis[q.peekFirst()]) { - q.addFirst(t); - } else { - q.add(t); - } + q.add(t); } } } @@ -89,15 +85,15 @@ public class 洛谷负环 { return false; } - static boolean[] vis = new boolean[10005]; + static boolean[] vis = new boolean[2005]; static ArrayDeque q = new ArrayDeque(); - static int[] count = new int[10005]; - static int[] dis = new int[10005]; + static int[] count = new int[2005]; + static int[] dis = new int[2005]; static int t, n, m, cnt = 1; - static int[] he = new int[10005]; - static int[] ne = new int[10005]; - static int[] e = new int[10005]; - static int[] w = new int[10005]; + static int[] he = new int[2005]; + static int[] ne = new int[6005]; + static int[] e = new int[6005]; + static int[] w = new int[6005]; static void add(int a, int b, int c) { e[cnt] = b; diff --git "a/ACWing/src/graph/\350\264\237\347\216\257/\345\215\225\350\257\215\347\216\257.java" "b/ACWing/src/graph/\350\264\237\347\216\257/\345\215\225\350\257\215\347\216\257.java" new file mode 100644 index 0000000..6e9db4d --- /dev/null +++ "b/ACWing/src/graph/\350\264\237\347\216\257/\345\215\225\350\257\215\347\216\257.java" @@ -0,0 +1,92 @@ +package graph.负环; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_44828887/article/details/107271849 + * 我们有 n 个字符串,每个字符串都是由 a∼z 的小写英文字母组成的。 + * 如果字符串 A 的结尾两个字符刚好与字符串 B 的开头两个字符相匹配, + * 那么我们称 A 与 B 能够相连(注意:A 能与 B 相连不代表 B 能与 A 相连)。 + * 我们希望从给定的字符串中找出一些, + * 使得它们首尾相连形成一个环串(一个串首尾相连也算), + * 我们想要使这个环串的平均长度最大。 + * 如下例: + */ +public class 单词环 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + char[] str; + while (sc.hasNext()) { + n = sc.nextInt(); + Arrays.fill(h, 0); + cnt = 1; + for (int i = 0; i < n; i++) { + str = sc.next().toCharArray(); + int len = str.length; + if (len >= 2) { + int left = (str[0] - 'a') * 26 + str[1] - 'a';//看做一个26进制数 + int right = (str[len - 2] - 'a') * 26 + str[len - 1] - 'a'; + add(left, right, len); + } + } + if (!check(0)) System.out.println("无解"); + else { + double l = 0, r = 1000; + while (r - l > 1e-5) { + double mid = (l + r) / 2; + if (check(mid)) l = mid; + else r = mid; + } + System.out.println(r); + } + } + } + + private static boolean check(double mid) { + Arrays.fill(st, false); + Arrays.fill(count, 0); + ArrayDeque q = new ArrayDeque(); + for (int i = 0; i < 676; i++) { + q.add(i); + st[i] = true; + } + int cn = 0; + while (!q.isEmpty()) { + int t = q.pollLast();//换成栈 + st[t] = true; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] < dis[t] + w[i] - mid) { + dis[j] = dis[t] + w[i] - mid; + count[j] = count[t] + 1; +// if (count[j] >= N) return true; + if (++cn > 30000) return true;//经验trick,或者换成把spfa的队列换成栈 + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + return false; + } + + static int n, cnt = 1, N = 700, M = 100100; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] w = new int[M]; + static int[] ne = new int[M]; + static double[] dis = new double[N]; + static int[] count = new int[N]; + static boolean[] st = new boolean[N]; + + static void add(int a, int b, int c) { + e[cnt] = b; + w[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt++; + } + +} diff --git "a/ACWing/src/graph/\350\264\237\347\216\257/\350\231\253\346\264\236.java" "b/ACWing/src/graph/\350\264\237\347\216\257/\350\231\253\346\264\236.java" index e3c07f9..342ba75 100644 --- "a/ACWing/src/graph/\350\264\237\347\216\257/\350\231\253\346\264\236.java" +++ "b/ACWing/src/graph/\350\264\237\347\216\257/\350\231\253\346\264\236.java" @@ -5,7 +5,33 @@ import java.util.Arrays; import java.util.Scanner; /** - * https://www.cnblogs.com/ctyakwf/p/12840842.html + * https://blog.csdn.net/qq_44828887/article/details/107271471 + * 农夫约翰在巡视他的众多农场时,发现了很多令人惊叹的虫洞。 + * 虫洞非常奇特,它可以看作是一条 单向 路径,通过它可以使你回到过去的某个时刻 + * (相对于你进入虫洞之前)。 + * 农夫约翰的每个农场中包含N片田地,M条路径(双向)以及W个虫洞。 + * 现在农夫约翰希望能够从农场中的某片田地出发,经过一些路径和虫洞回到过去, + * 并在他的出发时刻之前赶到他的出发地。 + * 他希望能够看到出发之前的自己。 + * 请你判断一下约翰能否做到这一点。 + * 下面我们将给你提供约翰拥有的农场数量F,以及每个农场的完整信息。 + * 已知走过任何一条路径所花费的时间都不超过10000秒, + * 任何虫洞将他带回的时间都不会超过10000秒。 + * 输入格式 + * 第一行包含整数F,表示约翰共有F个农场。 + * 对于每个农场,第一行包含三个整数N,M,W。 + * 接下来M行,每行包含三个整数S,E,T,表示田地S和E之间存在一条路径,经过这条路径所花的时间为T。 + * 再接下来W行,每行包含三个整数S,E,T,表示存在一条从田地S走到田地E的虫洞,走过这条虫洞,可以回到T秒之间。 + * 输出格式 + * 输出共F行,每行输出一个结果。 + * 如果约翰能够在出发时刻之前回到出发地,则输出“YES”,否则输出“NO”。 + * 数据范围 + * 1≤F≤5 + * 1≤N≤500, + * 1≤M≤2500, + * 1≤W≤200, + * 1≤T≤10000, + * 1≤S,E≤N * 2 * 3 3 1 * 1 2 2 @@ -16,6 +42,13 @@ import java.util.Scanner; * 1 2 3 * 2 3 4 * 3 1 8 + * out + * NO + * YES + * 由于虫洞是回到之前 所以可以看做是田地为点的负权值边。 + * 田地之间是双向边。 + * 只要检测到图中存在负环,那么就可以无限穿越到之前的时间, + * 而由于田地点之间是双向边,所以肯定能到达任意一个田地(也包括起点)。所以本题目就是判断图中是否存在负环。 */ public class 虫洞 { public static void main(String[] args) { diff --git "a/ACWing/src/graph/\350\264\237\347\216\257/\350\247\202\345\205\211\345\245\266\347\211\233.java" "b/ACWing/src/graph/\350\264\237\347\216\257/\350\247\202\345\205\211\345\245\266\347\211\233.java" new file mode 100644 index 0000000..dcc028f --- /dev/null +++ "b/ACWing/src/graph/\350\264\237\347\216\257/\350\247\202\345\205\211\345\245\266\347\211\233.java" @@ -0,0 +1,114 @@ +package graph.负环; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_44828887/article/details/107271543 + * https://blog.csdn.net/tomjobs/article/details/105252069 + * 给定一张L个点、P条边的有向图,每个点都有一个权值f[i],每条边都有一个权值t[i]。 + * 求图中的一个环,使“环上各点的权值之和”除以“环上各边的权值之和”最大。 + * 输出这个最大值。 + * 注意:数据保证至少存在一个环。 + * 输入格式 + * 第一行包含两个整数L和P。 + * 接下来L行每行一个整数,表示f[i]。 + * 再接下来P行,每行三个整数a,b,t[i],表示点a和b之间存在一条边,边的权值为t[i]。 + * 输出格式 + * 输出一个数表示结果,保留两位小数。 + * 数据范围 + * 2≤L≤1000, + * 2≤P≤5000, + * 1≤f[i],t[i]≤1000 + * 思路 + * 01分数规划。 + * 输入样例: + * 5 7 + * 30 + * 10 + * 10 + * 5 + * 10 + * 1 2 3 + * 2 3 2 + * 3 4 5 + * 3 5 2 + * 4 5 5 + * 5 1 3 + * 5 2 2 + * 输出样例: + * 6.00 + * 每个点都有权值,每条边都有权值,求一个环, + * 使得每个点的权值和除以每条边的权值和最大 + * 01分数规划,∑fi/∑ti最大,可以二分找正环 + */ +public class 观光奶牛 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + for (int i = 1; i <= n; i++) { + wf[i] = sc.nextInt(); + } + int a, b, c; + while (m-- != 0) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + add(a, b, c); + } + double l = 0, r = 1e6; + while (r - l > 1e-4) {//保留两位小数,多加2位, + double mid = (l + r) / 2; + if (check(mid)) l = mid; + else r = mid; + } + System.out.printf("%.2f", l); + } + + private static boolean check(double mid) { + Arrays.fill(st, false); + Arrays.fill(count, 0); + Arrays.fill(dis, 0); + ArrayDeque q = new ArrayDeque(); + for (int i = 1; i <= n; i++) { + q.add(i); + st[i] = true; + } + while (!q.isEmpty()) { + int t = q.poll(); + st[t] = false; + for (int i = h[t]; i != 0; i = ne[i]) { + int j = e[i]; + if (dis[j] < dis[t] + wf[t] - mid * wt[i]) { + dis[j] = dis[t] + wf[t] - mid * wt[i]; + count[j] = count[t] + 1; + if (count[j] >= n) return true; + if (!st[j]) { + q.add(j); + st[j] = true; + } + } + } + } + return false; + } + + private static void add(int a, int b, int c) { + e[cnt] = b; + wt[cnt] = c; + ne[cnt] = h[a]; + h[a] = cnt++; + } + + static int n, m, N = 1010, M = 10100, cnt = 1; + static int[] h = new int[N]; + static int[] e = new int[M]; + static int[] wf = new int[N]; + static int[] ne = new int[M]; + static int[] wt = new int[M]; + static double[] dis = new double[N]; + static int[] count = new int[N]; + static boolean[] st = new boolean[N]; +} diff --git "a/ACWing/src/graph/\350\264\237\347\216\257/\350\264\237\347\216\257.md" "b/ACWing/src/graph/\350\264\237\347\216\257/\350\264\237\347\216\257.md" index 0898acd..f28a5d5 100644 --- "a/ACWing/src/graph/\350\264\237\347\216\257/\350\264\237\347\216\257.md" +++ "b/ACWing/src/graph/\350\264\237\347\216\257/\350\264\237\347\216\257.md" @@ -14,3 +14,13 @@ 如果某个点的最短路所包含的边数大于等于n, 则也说明存在环 O(n)推荐 + +考虑1~n组成负环,第一种做法是O(n^2) n(n-1)+1次 + +初始化,queue加入所有节点,看做超级源点连接每个点权值都为0 +dis不用初始化 +如果有负环,dis赋值为有限值,一直减结果必然会变成负无穷 + +只有BellmanFord 和Floyd才有 0x3f3f3f3f/2 + +spfa判断环,把队列换成栈跑的更快 \ No newline at end of file diff --git "a/ACWing/src/\346\225\260\345\255\246/\345\272\217\345\210\227\347\232\204\347\254\254k\344\270\252\346\225\260.java" "b/ACWing/src/\346\225\260\345\255\246/\345\272\217\345\210\227\347\232\204\347\254\254k\344\270\252\346\225\260.java" new file mode 100644 index 0000000..e3c78c0 --- /dev/null +++ "b/ACWing/src/\346\225\260\345\255\246/\345\272\217\345\210\227\347\232\204\347\254\254k\344\270\252\346\225\260.java" @@ -0,0 +1,58 @@ +package 数学; + +import java.util.Scanner; + +/** + * https://blog.csdn.net/njuptACMcxk/article/details/107328091 + * BSNY 在学等差数列和等比数列,当已知前三项时,就可以知道是等差数列还是等比数列。 + * 现在给你 整数 序列的前三项,这个序列要么是等差序列,要么是等比序列,你能求出第 k 项的值吗。 + * 如果第 k 项的值太大,对其取模 200907。 + * 输入格式 + * 第一行一个整数 T,表示有 T 组测试数据; + * 对于每组测试数据,输入前三项 a,b,c,然后输入 k。 + * 输出格式 + * 对于每组数据,输出第 k 项取模 200907 的值。 + * 数据范围 + * 1≤T≤100,1≤a≤b≤c≤109,1≤k≤1091≤T≤100,1≤a≤b≤c≤10^9 + * ,1≤k≤10^9 + * 输入样例: + * 2 + * 1 2 3 5 + * 1 2 4 5 + * 输出样例: + * 5 + * 16 + */ +public class 序列的第k个数 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int a, b, c, d, k; + d = sc.nextInt(); + for (int i = 0; i < d; i++) { + a = sc.nextInt(); + b = sc.nextInt(); + c = sc.nextInt(); + k = sc.nextInt(); + if (a + c == 2 * b) { + System.out.println((a + (k - 1) * (b - a)) % mod); + } else { + System.out.println((a * qmi((b / a), k-1)) % mod); + } + } + + } + + static long qmi(long a, long b) { + long res = 1; + while (b != 0) { + if ((b & 1) == 1) { + res = (res * a) % mod; + } + a = (a * a) % mod; + b >>= 1; + } + return res; + } + + static int mod = 200907; +} diff --git "a/ACWing/src/\346\225\260\345\255\246/\350\266\212\347\213\261.java" "b/ACWing/src/\346\225\260\345\255\246/\350\266\212\347\213\261.java" new file mode 100644 index 0000000..723cc19 --- /dev/null +++ "b/ACWing/src/\346\225\260\345\255\246/\350\266\212\347\213\261.java" @@ -0,0 +1,44 @@ +package 数学; + +import java.util.Scanner; + +/** + * https://www.acwing.com/solution/acwing/content/12579/ + * https://www.hzxueyan.com/archives/85/ + * 监狱有连续编号为 11 到 nn 的 nn 个房间,每个房间关押一个犯人。 + * 有 mm 种宗教,每个犯人可能信仰其中一种。 + * 如果相邻房间的犯人信仰的宗教相同,就可能发生越狱。 + * 求有多少种状态可能发生越狱。 + * 输入 + * 共一行,包含两个整数 mm 和 nn。 + * 输出 + * 可能越狱的状态数,对 100003取余。 + * 数据范围 + * 输入样例 + * 2 3 + * 输出样例 + * 6 + * 样例解释 + * 所有可能的 66 种状态为:(000)(001)(011)(100)(110)(111)(000)(001)(011)(100)(110)(111)。 + */ +public class 越狱 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + m = sc.nextInt(); + n = sc.nextInt(); + System.out.println((qmi(m, n) - m * qmi(m - 1, n - 1)) % mod); + } + + static long qmi(long a, long b) { + long res = 1; + while (b != 0) { + if ((b & 1) == 1) res = res * a % mod; + a = a * a % mod; + b >>= 1; + } + return res; + } + + static int n, m, mod = 100003; + +} diff --git "a/ACWing/src/\346\225\260\345\255\246/\351\230\266\344\271\230\345\210\206\350\247\243.java" "b/ACWing/src/\346\225\260\345\255\246/\351\230\266\344\271\230\345\210\206\350\247\243.java" index 8cc1a9f..638f7a8 100644 --- "a/ACWing/src/\346\225\260\345\255\246/\351\230\266\344\271\230\345\210\206\350\247\243.java" +++ "b/ACWing/src/\346\225\260\345\255\246/\351\230\266\344\271\230\345\210\206\350\247\243.java" @@ -1,10 +1,47 @@ package 数学; +import java.util.Scanner; + /** - * + * https://blog.csdn.net/aoying6521/article/details/101785682 + * https://www.acwing.com/solution/acwing/content/982/ + * https://www.hzxueyan.com/archives/83/ + * 给定整数 N ,试把阶乘 N!分解质因数,按照算术基本定理的形式输出分解结果中的pi和 ci + * 即可。 + * 输入样例 + * 5 + * 输出样例 + * 2 3 + * 3 1 + * 5 1 */ public class 阶乘分解 { public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + init(n); + for (int i = 0; i < cnt; i++) { + int t = p[i]; + int s = 0; + for (int j = n; j != 0; j /= t) { + s += j / t; + } + System.out.println(t + " " + s); + } + } + static void init(int n) { + + for (int i = 2; i <= n; i++) { + if (!st[i]) p[cnt++] = i; + for (int j = 0; p[j] <= n / i; j++) { + st[p[j] * i] = true; + if (i % p[j] == 0) break; + } + } } + + static int n, cnt = 0; + static boolean[] st = new boolean[(int) (1e6 + 10)]; + static int[] p = new int[(int) (1e6 + 10)]; } diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.java" similarity index 98% rename from "ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204.java" rename to "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.java" index cb6a482..7d27b3f 100644 --- "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204.java" +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.java" @@ -1,4 +1,4 @@ -package 线段树; +package 树状数组; import java.io.*; import java.util.StringTokenizer; diff --git "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.md" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.md" new file mode 100644 index 0000000..c99288f --- /dev/null +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204.md" @@ -0,0 +1,14 @@ +###树状数组 +```` +1.快速求前缀和 O(log n) +2.修改某一个数 O(log n) + +对比前缀和 +修改单点修改O(n) +查询O(1) + +基于二进制的想法解决问题 +x=2^ik+2^i(k-1)+...+2^i +ik>=i(k-1)>=...>=i +1~x表示 + diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" similarity index 93% rename from "ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" rename to "ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" index 09bd33c..f5650f6 100644 --- "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\240\221\347\212\266\346\225\260\347\273\204\345\214\272\351\227\264\344\277\256\346\224\271.java" @@ -1,4 +1,4 @@ -package 线段树; +package 树状数组; import java.io.*; import java.util.StringTokenizer; @@ -38,7 +38,7 @@ public class 树状数组区间修改 { n = nextInt(); m = nextInt(); for (int i = 1; i <= n; i++) { - cha[i] = nextInt(); + a[i] = nextInt(); } int x, y, z, t; while (m-- != 0) { @@ -51,7 +51,7 @@ public class 树状数组区间修改 { add(y + 1, -z); } else if (t == 2) { x = nextInt(); - bw.write((ask(x) + cha[x]) + "\n"); + bw.write((ask(x) + a[x]) + "\n"); } } bw.flush(); @@ -59,7 +59,7 @@ public class 树状数组区间修改 { static int maxn = 500001, n, m; static long[] tree = new long[maxn]; - static long[] cha = new long[maxn]; + static long[] a = new long[maxn]; //差分数组 static void add(int s, int value) { diff --git "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\245\274\345\205\260\345\233\276\350\205\276.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\245\274\345\205\260\345\233\276\350\205\276.java" new file mode 100644 index 0000000..484814e --- /dev/null +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\346\245\274\345\205\260\345\233\276\350\205\276.java" @@ -0,0 +1,74 @@ +package 树状数组; + +import java.util.Arrays; +import java.util.Scanner; + +/** + * 题目 + * https://www.acwing.com/problem/content/description/243/ + * https://www.acwing.com/solution/acwing/content/1008/ + * 巧妙想法,也可以求逆序数!!! + * 建树状数组O(nlogn) + * 天才想法太巧妙啊 + */ +public class 楼兰图腾 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + for (int i = 1; i <= n; i++) { + a[i] = sc.nextInt(); +// max_value = Math.max(a[i], max_value);//记录数组最大值 + } + /** + * 正序循环,巧妙想法,也可以求逆序数 + * 这里great记录左边有多少个比它大的, + * lower记录左边有多少比它小的 + */ + for (int i = 1; i <= n; i++) { + int y=a[i]; + great[i] = ask(n) - ask(y); + lower[i] = ask(y-1); + add(y, 1); + } + Arrays.fill(c, 0); + /** + * 倒序循环这里great记录右边有多少个比它大的, + * lower记录右边有多少比它小的 + */ + long res1 = 0, res2 = 0; + for (int i = n; i != 0; i--) { + int y = a[i]; + res1 += great[i] * (ask(n) - ask(y)); + res2 += lower[i] * ask(y - 1); + add(y, 1); + } + System.out.println(res1 + " " + res2); + + } + + static int N = (int) (2e5 + 200), n, max_value; + static int[] c = new int[N]; + static int[] a = new int[N]; + static long[] great = new long[N]; + static long[] lower = new long[N]; + + static long ask(int x) { + long ans = 0; + while (x != 0) { + ans += c[x]; + x -= lowbit(x); + } + return ans; + } + + static void add(int x, int value) { + for (int i = x; i <= n; i += lowbit(i)) { + c[i] += value; + } + } + + private static int lowbit(int x) { + return x & (-x); + } + +} diff --git "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" new file mode 100644 index 0000000..949ffb1 --- /dev/null +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\350\260\234\344\270\200\346\240\267\347\232\204\347\211\233.java" @@ -0,0 +1,111 @@ +package 树状数组; + +import java.io.*; +import java.util.StringTokenizer; + +/** + * https://blog.csdn.net/mrgaohaihang/article/details/107146133 + * 有n头奶牛,已知它们的身高为 1~n 且各不相同,但不知道每头奶牛的具体身高。 + * 现在这n头奶牛站成一列,已知第i头牛前面有Ai + * 头牛比它低,求每头奶牛的身高。 + * 输入格式 + * 第1行:输入整数n。 + * 第2…n行:每行输入一个整数Ai + * ,第i行表示第i头牛前面有Ai + * 头牛比它低。 + * (注意:因为第1头牛前面没有牛,所以并没有将它列出) + * 输出格式 + * 输出包含n行,每行输出一个整数表示牛的身高。 + * 第i行输出第i头牛的身高。 + * 数据范围 + * 1≤n≤105 + * 输入样例: + * 5 + * 1 + * 2 + * 1 + * 0 + * 输出样例: + * 2 + * 4 + * 5 + * 3 + * 1 + * 设A1 A2...An + * 倒着往前推, + * 那么低An位置,就是第An+1小的数 + * 第A(i)位置,有A(i)头比它少,就是剩下的第A(i)小的数 + * (1)从剩余的数中找到第k小的数 + * (2)删除某个数 + * 树状数组优化! + * 树状数组,A1~An=1树状数组维护前缀和 + * 令树状数组每一个都等于1,代表这个数可用 + * sum(x)代表1~x有多少个可用 + * 则求第k小的数代表,可以二分求最小的sum(x)的x使得sum(x)=k + */ +public class 谜一样的牛 { + public static void main(String[] args) throws IOException { + n = nextInt(); + for (int i = 2; i <= n; i++) { + a[i] = nextInt(); + } + for (int i = 1; i <= n; i++) { + add(i, 1); + } + for (int i = n; i != 0; i--) { + int l = 1, r = n, k = a[i] + 1; + while (l < r) { + int mid = (l + r) / 2; + if (ask(mid) >= k) r = mid; + else l = mid + 1; + } + ans[i] = r; + add(r, -1); + } + for (int i = 1; i <= n; i++) { + bw.write(ans[i]+"\n"); + } + bw.flush(); + + } + + static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + static StringTokenizer st = new StringTokenizer(""); + + static String next() throws IOException { + while (!st.hasMoreTokens()) { + st = new StringTokenizer(br.readLine()); + } + return st.nextToken(); + } + + static int nextInt() throws IOException { + return Integer.parseInt(next()); + } + + static int n; + static int[] tr = new int[(int) (1e5 + 10)]; + static int[] a = new int[(int) (1e5 + 10)]; + static int[] ans = new int[(int) (1e5 + 10)]; + + static int lowbit(int x) { + return x & -x; + } + + static void add(int x, int v) { + for (int i = x; i <= n; i += lowbit(i)) { + tr[i] += v; + } + } + + static int ask(int x) { + int res = 0; + while (x != 0) { + res += tr[x]; + x -= lowbit(x); + } + return res; + } + +} diff --git "a/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\351\200\206\345\272\217\346\225\260.java" "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\351\200\206\345\272\217\346\225\260.java" new file mode 100644 index 0000000..d4b9d34 --- /dev/null +++ "b/ACWing/src/\346\240\221\347\212\266\346\225\260\347\273\204/\351\200\206\345\272\217\346\225\260.java" @@ -0,0 +1,73 @@ +package 树状数组; + +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/m0_38033475/article/details/80330157 + * 离散化+树状数组求逆序对 + * 5 + * 13 6 9 11 5 + */ +public class 逆序数 { + static class node implements Comparable { + int v, index; + + public node(int v, int index) { + this.v = v; + this.index = index; + } + + @Override + public int compareTo(node node) { + return v - node.v; + } + } + + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + for (int i = 1; i <= n; i++) { + de[i] = new node(sc.nextInt(), i); +// max_value = Math.max(a[i], max_value);//记录数组最大值 + } + Arrays.sort(de, 1, n+1); + /** + * 正序循环,巧妙想法,也可以求逆序数 + * 这里great记录左边有多少个比它大的, + * lower记录左边有多少比它小的 + */ + int res = 0; + for (int i = 1; i <= n; i++) { + int y = de[i].index; + res += ask(n) - ask(y); + add(y, 1); + } + System.out.println(res); + } + + static int N = (int) (2e5 + 200), n; + static int[] c = new int[N]; + static node[] de = new node[N]; + + static long ask(int x) { + long ans = 0; + while (x != 0) { + ans += c[x]; + x -= lowbit(x); + } + return ans; + } + + static void add(int x, int value) { + for (int i = x; i <= n; i += lowbit(i)) { + c[i] += value; + } + } + + private static int lowbit(int x) { + return x & (-x); + } + +} diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\345\215\225\347\202\271\346\233\264\346\226\260\345\214\272\351\227\264\346\237\245\350\257\242.java" "b/ACWing/src/\347\272\277\346\256\265\346\240\221/\345\215\225\347\202\271\346\233\264\346\226\260\345\214\272\351\227\264\346\237\245\350\257\242.java" new file mode 100644 index 0000000..f149808 --- /dev/null +++ "b/ACWing/src/\347\272\277\346\256\265\346\240\221/\345\215\225\347\202\271\346\233\264\346\226\260\345\214\272\351\227\264\346\237\245\350\257\242.java" @@ -0,0 +1,21 @@ +package 线段树; + +//线段树 +public class 单点更新区间查询 { + public static void main(String[] args) { + + } + + static int[] max = new int[800010]; + + static void build(int k, int l, int r) { + if (l == r) { + + return; + } + int mid = l + r >> 1; + build(k << 1, l, mid); + build(k << 1 | 1, mid + 1, r); + + } +} diff --git "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\245\274\345\205\260\345\233\276\350\205\276.java" "b/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\245\274\345\205\260\345\233\276\350\205\276.java" deleted file mode 100644 index c560120..0000000 --- "a/ACWing/src/\347\272\277\346\256\265\346\240\221/\346\245\274\345\205\260\345\233\276\350\205\276.java" +++ /dev/null @@ -1,87 +0,0 @@ -package 线段树; - -import java.util.Arrays; -import java.util.Scanner; - -/** - * 题目https://www.acwing.com/problem/content/description/243/ - * https://www.acwing.com/solution/acwing/content/1008/ - */ -public class 楼兰图腾 { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - n = sc.nextInt(); - for (int i = 1; i <= n; i++) { - a[i] = sc.nextInt(); - max_value = Math.max(a[i], max_value);//记录数组最大值 - } - res1(); - System.out.println(sumans()); - - } - - static int N = (int) (2e5 + 200), n, max_value; - static int[] c = new int[N]; - static int[] a = new int[N]; - static long[] l = new long[N]; - static long[] r = new long[N]; - - static long ask(int x) { - long ans = 0; - while (x != 0) { - ans += c[x]; - x -= lowbit(x); - } - return ans; - } - - static void add(int i, int value) { - for (; i <= n; i += lowbit(i)) { - c[i] += value; - } - } - - private static int lowbit(int x) { - return x & (-x); - } - - static void res1() { - Arrays.fill(c, 0); - for (int i = n; i != 0; i--) { - r[i] = ask(max_value) - ask(a[i]); - System.out.println(r[i]); - add(a[i], 1); - } - System.out.println(); - Arrays.fill(c, 0); - for (int i = 1; i <= n; i++) { - l[i] = ask(max_value) - ask(a[i]); - System.out.println(l[i]); - add(a[i], 1); - } - } - - static void res2() { - Arrays.fill(c, 0); - for (int i = n; i != 0; i--) { - r[i] = ask(a[i - 1]); - System.out.println(r[i]); - add(a[i], 1); - } - System.out.println(); - Arrays.fill(c, 0); - for (int i = 1; i <= n; i++) { - l[i] = ask(a[i] - 1); - System.out.println(l[i]); - add(a[i], 1); - } - } - - static long sumans() { - long ans = 0; - for (int i = 1; i <= n; i++) { - ans += l[i] * r[i]; - } - return ans; - } -} -- GitLab