提交 0a435d14 编写于 作者: qq_36480062's avatar qq_36480062

c

上级 300f98cc
......@@ -31,4 +31,28 @@ dp分析:
i~k取最小且k~j取最小:d[k-1][i][k]+d[k-1][k][j]
所有路径不包含节点k的路径:d[k-1][i][j]
直接去掉最高维,代码等价
d[i,j]=min( d[i,j] , d[i,k]+d[k,j] )
\ No newline at end of file
d[i,j]=min( d[i,j] , d[i,k]+d[k,j] )
传递闭包
给定一个有向图,无向图也可以看做有向图
a可以到b,b可以到c,
那么给a到c连一条边
所有能间接到达的点,都给它们连一条直接的边!
所有这样的边都连上,就成为原图的传递闭包
Floyd可以用O(n^3)求出传递闭包,邻接矩阵
1.初始化d(i,j)=g(i,j)
g(i,j){
存在i->j这条边 1
不存在i->j这条边 0
}
2.Floyd
for k
for i
for j
if( d(i,k)=1 & d(k,j)=1)
d(i,j)=1
如果i能到k,k能到j,说明i能到j,那么把d(i,j)置为1
说明g(i,j)可以间接到达,连一条边
package graph.Floyd;
import java.util.Arrays;
import java.util.Scanner;
/**
*https://blog.csdn.net/qq_30277239/article/details/107453694
* 给定 n 个变量和 m 个不等式。其中 n 小于等于26,变量分别用前 n 的大写英文字母表示。
* 不等式之间具有传递性,即若 A>B 且 B>C ,则 A>C。
* 请从前往后遍历每对关系,每次遍历时判断:
* 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
* 如果发生矛盾,则结束循环,输出有矛盾;
* 如果循环结束时没有发生上述两种情况,则输出无定解。
* 输入格式
* 输入包含多组测试数据。
* 每组测试数据,第一行包含两个整数n和m。
* 接下来m行,每行包含一个不等式,不等式全部为小于关系。
* 当输入一行0 0时,表示输入终止。
* 输出格式
* 每组数据输出一个占一行的结果。
* 结果可能为下列三种之一:
* 如果可以确定两两之间的关系,则输出 "Sorted sequence determined after t relations: yyy...y.",其中't'指迭代次数,'yyy...y'是指升序排列的所有变量。
* 如果有矛盾,则输出: "Inconsistency found after t relations.",其中't'指迭代次数。
* 如果没有矛盾,且不能确定两两之间的关系,则输出 "Sorted sequence cannot be determined."。
* 数据范围
* 2≤n≤26,变量只可能为大写字母A~Z。
* 输入样例1:
* 4 6
* A<B
* A<C
* B<C
* C<D
* B<D
* A<B
* 3 2
* A<B
* B<A
* 26 1
* A<Z
* 0 0
* 输出样例1:
* Sorted sequence determined after 4 relations: ABCD.
* Inconsistency found after 2 relations.
* Sorted sequence cannot be determined.
* 输入样例2:
* 6 6
* A<F
* B<D
* C<E
* F<D
* D<E
* E<F
* 0 0
* 输出样例2:
* Inconsistency found after 6 relations.
* 输入样例3:
* 5 5
* A<B
* B<C
* C<D
* D<E
* E<A
* 0 0
* 输出样例3:
* Sorted sequence determined after 4 relations: ABCDE.
* 本题考察Floyd算法在传递闭包问题上的应用。给定若干对元素和若干对二元关系,并且关系具有传递性,通过传递性推导出尽量多的元素之间的关系的问题被称为传递闭包。比如a < b,b < c,就可以推导出a < c,如果用图形表示出这种大小关系,就是a到b有一条有向边,b到c有一条有向边,可以推出a可以到达c,找出图中各点能够到达点的集合,就类似于Floyd算法求图中任意两点间的最短距离。Floyd求解传递闭包问题的代码如下:
* void floyd(){
* for(int k = 0;k < n;k++)
* for(int i = 0;i < n;i++)
* for(int j = 0;j < n;j++)
* f[i][j] |= f[i][k] & f[k][j];
* }
* 只是对原来算法在状态转移方程上略加修改 就能够求解传递闭包问题了。
* f[i][j] = 1表示i可以到达j ( i < j),f[i][j] = 0表示i不可到达j。
* 只要i能够到达k并且k能够到达j,那么i就能够到达j,这就是上面代码的含义。
* 对于本题而言,给定n个元素和一堆二元关系,依次读取每个二元关系,
* 在读取第i个二元关系后,如果可以确定n个元素两两间的大小关系了,
* 就输出在几对二元关系后可以确定次序,并且次序是什么;如果出现了矛盾,
* 就是A < B并且B < A这种情况发生了就输出多少对二元关系后开始出现矛盾;
* 如果遍历完所有的二元关系还不能确定所有元素间的大小关系,就输出无法确定。
* 可以发现,题目描述要求按顺序遍历二元关系,一旦前i个二元关系可以确定次序了就不再遍历了,
* 即使第i + 1对二元关系就会出现矛盾也不去管它了。对于二元关系的处理和之前的做法一样,
* A < B,就将f[0][1]设为1,题目字母只会在A到Z间,因此可以映射为0到25这26个元素,
* 如果f[0][1] = f[1][0] = 1,就可以推出f[0][0] = 1,此时A < B并且A > B发生矛盾,
* 因此在f[i][i]= 1时发生矛盾。
* 下面详细分析下求解的步骤:首先每读取一对二元关系,就执行一遍Floyd算法求传递闭包,
* 然后执行check函数判断下此时是否可以终止遍历,如果发生矛盾或者次序全部被确定就终止遍历,
* 否则继续遍历。在确定所有的次序后,需要输出偏序关系,因此需要执行下getorder函数。
* 注意这里的终止遍历仅仅是不再针对新增的二元关系去求传递闭包,循环还是要继续的,
* 需要读完数据才能继续读下一组数据。
* 下面设计check函数和getorder函数。
* int check(){
* for(int i = 0;i < n;i++)
* if(f[i][i]) return 0;
* for(int i = 0;i < n;i++){
* for(int j = 0;j < i;j++){
* if(!f[i][j] && !f[j][i]) return 1;
* }
* }
* return 2;
* }
* 如果f[i][i] = 1就发生矛盾了,可以返回了;
* 如果f[i][j] = f[j][i] = 0表示i与j之间的偏序关系还没有确定下来,
* 就需要继续读取下一对二元关系;如果所有的关系都确定了,就返回2。
* string getorder(){
* char s[26];
* for(int i = 0;i < n;i++){
* int cnt = 0;
* for(int j = 0;j < n;j++) cnt += f[i][j];
* s[n - cnt - 1] = i + 'A';
* }
* return string(s,s + n);
* }
* 确定所有元素次序后如何判断元素i在第几个位置呢?f[i][j] = 1表示i < j,
* 因此计算下下i小于元素的个数cnt,就可以判定i是第cnt + 1大的元素了。
*
* 1.显然如果A<A自己小于自己就是矛盾,对应图论就是d[i,i]=1
* A<B小于看做 A->B的边为1 d(A,B)=1
* 2.唯一确定,d(i,j) i不等于j d(i,j) 和d(j,i)只有一个是1
* 3.顺序不唯一
*
*
*/
public class 排序 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int type = 0, t = 0;
n = sc.nextInt();
m = sc.nextInt();
for (int i = 0; i < 26; i++) {
Arrays.fill(g[i], false);
}
for (int i = 1; i <= m; i++) {
String s = sc.next();
int a = s.charAt(0) - 'A', b = s.charAt(2) - 'A';
if (type == 0) {
g[a][b] = true;
floyd();
type = check();
if (type != 0) t = i;
}
}
if (type != 0) {
System.out.print("Sorted sequence cannot be determined.\n");
} else if (type == 2) System.out.printf("Inconsistency found after %d relations.\n", t);
else {
Arrays.fill(st, false);
System.out.printf("Sorted sequence determined after %d relations:", t);
for (int i = 0; i < n; i++) {
System.out.printf("%c", getmin());
}
System.out.println(".");
}
}
}
static int n, m, N = 26;
static boolean[][] g = new boolean[N][N], d = new boolean[N][N];
static boolean[] st = new boolean[N];
static char getmin() {
for (int i = 0; i < n; i++) {
if (!st[i]) {
boolean f = true;
for (int j = 0; j < n; j++) {
if (!st[i] && d[j][i]) {
f = false;
break;
}
}
if (f) {
st[i] = true;
return (char) ('A' + i);
}
}
}
return ' ';
}
static void floyd() {
d = Arrays.copyOf(g, d.length);
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
d[i][j] |= d[i][k] && d[k][j];
}
}
}
}
static int check() {
for (int i = 0; i < n; i++) {
if (d[i][i]) return 2;
}//i<i矛盾
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (!d[i][j] && !d[j][i]) return 0;
}
}
return 1;
}
}
package graph.Floyd;
/**
* https://blog.csdn.net/qq_30277239/article/details/107702663
* 给定一张无向图,求图中一个至少包含3个点的环,环上的节点不重复,并且环上的边的长度之和最小。
* 该问题称为无向图的最小环问题。
* 你需要输出最小环的方案,若最小环不唯一,输出任意一个均可。
* 输入格式
* 第一行包含两个整数N和M,表示无向图有N个点,M条边。
* 接下来M行,每行包含三个整数u,v,l,表示点u和点v之间有一条边,边长为l。
* 输出格式
* 输出占一行,包含最小环的所有节点(按顺序输出),如果不存在则输出’No solution.’。
* 数据范围
* 1≤N≤100,
* 1≤M≤10000,
* 1≤l<500
* 输入样例:
* 5 7
* 1 4 1
* 1 3 300
* 3 1 10
* 1 2 16
* 2 3 100
* 2 5 15
* 5 3 20
* 输出样例:
* 1 3 5 2
* 如图所示,设环上编号最大的节点编号是k,i和j分别是环上与k相邻的两个节点。根据之前对floyd算法的推导,f[k][i][j]表示图上i经过编号不超过k的节点到达j的最短路径长度,观察上图可以发现,环的长度等于i到j的最短距离加上g[i][k]再加上g[k][j],设环的长度为ans,则ans = f[i][j] + g[i][k] + g[k][j],这里的f[i][j]是对f[k-1][i][j]降维后的结果,为什么是f[k-1][i][j]而不是f[k][i][j],因为前面已经规定k是最大的节点,环上其他的节点必然都小于k。为什么要这么规定,这种思路是如何来的?后面会分析这种思路的由来。
*
* 我们知道,floyd算法最外层k刚刚循环到第k次时,f[i][j]存储的还是i经过编号不超过k-1的节点到达j的最短路径长度,此时的f[i][j]正是我们所需要的,因此在第k次循环开始时,由k,i,j加上i到j中间的节点构成的最小环长度就是f[i][j] + g[i][k] + g[k][j],我们还是用三层循环去枚举所有的情况,最终就可以求出最小环的长度。
*/
public class 最小环 {
public static void main(String[] args) {
}
}
package graph.Floyd;
import java.util.Scanner;
/**
* https://blog.csdn.net/qq_30277239/article/details/107301496
* https://www.cnblogs.com/ctyakwf/p/12829458.html
* 农民John的农场里有很多牧区,有的路径连接一些特定的牧区。
* 一片所有连通的牧区称为一个牧场。
* 但是就目前而言,你能看到至少有两个牧区不连通。
* 现在,John想在农场里添加一条路径(注意,恰好一条)。
* 一个牧场的直径就是牧场中最远的两个牧区的距离(本题中所提到的所有距离指的都是最短的距离)。
* 考虑如下的两个牧场,每一个牧区都有自己的坐标:
* 图 1 是有 5 个牧区的牧场,牧区用“*”表示,路径用直线表示。
* 图 1 所示的牧场的直径大约是 12.07106, 最远的两个牧区是 A 和 E,
* 它们之间的最短路径是 A-B-E。
* 图 2 是另一个牧场。
* 这两个牧场都在John的农场上。
* John将会在两个牧场中各选一个牧区,然后用一条路径连起来,
* 使得连通后这个新的更大的牧场有最小的直径。
* 注意,如果两条路径中途相交,我们不认为它们是连通的。
* 只有两条路径在同一个牧区相交,我们才认为它们是连通的。
* 现在请你编程找出一条连接两个不同牧场的路径,使得连上这条路径后,所有牧场(生成的新牧场和原有牧场)中直径最大的牧场的直径尽可能小。
* 输出这个直径最小可能值。
* 输入格式
* 第 1 行:一个整数 N, 表示牧区数;
* 第 2 到 N+1 行:每行两个整数 X,Y, 表示 N 个牧区的坐标。每个牧区的坐标都是不一样的。
* 第 N+2 行到第 2*N+1 行:每行包括 N 个数字 ( 0或1 ) 表示一个对称邻接矩阵。
* 例如,题目描述中的两个牧场的矩阵描述如下:
* A B C D E F G H
* A 0 1 0 0 0 0 0 0
* B 1 0 1 1 1 0 0 0
* C 0 1 0 0 1 0 0 0
* D 0 1 0 0 1 0 0 0
* E 0 1 1 1 0 0 0 0
* F 0 0 0 0 0 0 1 0
* G 0 0 0 0 0 1 0 1
* H 0 0 0 0 0 0 1 0
* 输入数据中至少包括两个不连通的牧区。
* 输出格式
* 只有一行,包括一个实数,表示所求答案。
* 数字保留六位小数。
* 数据范围
* 1≤N≤150,
* 0≤X,Y≤10^5
* 输入样例:
* 8
* 10 10
* 15 10
* 20 10
* 15 15
* 20 15
* 30 15
* 25 10
* 30 10
* 01000000
* 10111000
* 01001000
* 01001000
* 01110000
* 00000010
* 00000101
* 00000010
* 输出样例:
* 22.071068
*/
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);
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
int a, b;
for (int i = 0; i < n; i++) {
a = sc.nextInt();
b = sc.nextInt();
q[i] = new node(a, b);
}
for (int i = 0; i < n; i++) {
g[i] = sc.next().toCharArray();
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i != j) {
if (g[i][j] == '1') d[i][j] = get_dist(q[i], q[j]);
else
d[i][j] = inf;
}
}
}
//floyd
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (d[i][j] < inf) {
maxd[i] = Math.max(maxd[i], d[i][j]);
}
}
}
double res1 = 0;
for (int i = 0; i < n; i++) {
res1 = Math.max(res1, maxd[i]);
}
double res2 = inf;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (d[i][j] >= inf) {
res2 = Math.min(res2, get_dist(q[i], q[j]) + maxd[i] + maxd[j]);
}
}
}
System.out.printf("%.6f", Math.max(res1, res2));
}
static double get_dist(node a, node b) {
double dx = a.x - b.x, dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
static int n, N = 150;
static double inf = 1e20;
static node[] q = new node[N];
static char[][] g = new char[N][N];
static double[][] d = new double[N][N];//邻接矩阵
static double[] maxd = new double[N];
static class node {
int x, y;
public node(int x, int y) {
this.x = x;
this.y = y;
}
}
}
......@@ -23,6 +23,17 @@ import java.util.Scanner;
* 输出样例:
* 6
* 该题必定有解,显然全放进去,一定满足要求
* 显然0~50000 下标不好用,同时+1, 得到1~50001
* 往右平移一格,不影响答案,空出0,
* 利用前缀和,
* S0=0
* Si表示从1~i中被选出的数的个数
* 则S50001的最小值,表示1~50001被选出数的个数,则是答案
* 找不等关系,显然:
* 1. Si>=S(i-1) 1<=i<=50001 i-1向i连一条长度为0的边,这个条件存在意味着,存在源点能遍历到所有点,所有边
* 2. Si-Si-1<=1 => S(i-1)>=Si-1 表示第i个数选没选,显然每个数只能选一次
* 3. [a,b]中必须选c个, =>Sb-S(a-1)>=c => Sb>=S(a-1)+C
* 令S50001最小,最长路
* 思路:
* 先将不等式写出来
* 将所有区间向右移一位,这样如果1-2有一条边 3-4有一条边,
......@@ -45,7 +56,9 @@ public class 区间 {
n = sc.nextInt();
for (int i = 1; i <= 50001; i++) {
add(i - 1, i, 0);
//Si>=S(i-1)
add(i, i - 1, -1);
//S(i-1)>=Si-1
}
int a, b, c;
while (n-- != 0) {
......@@ -55,14 +68,17 @@ public class 区间 {
a++;
b++;
add(a - 1, b, c);
//Sb>=S(a-1)+C
}
spfa();
System.out.println(dis[50001]);
}
private static void spfa() {
int inf = Integer.MIN_VALUE / 2 - 10000;
q.add(0);
Arrays.fill(dis, -Integer.MAX_VALUE / 2);
Arrays.fill(dis, inf);
//求最小值,所以初始化为负无穷,看三角不等式,更新规则,得出
st[0] = true;
dis[0] = 0;
while (!q.isEmpty()) {
......@@ -82,7 +98,7 @@ public class 区间 {
}
static int n, m, N = 50010, M = 150010, count = 1;
static int n, m, N = 50010, M = 150010, idx = 1;
static int[] h = new int[N];
static int[] e = new int[M];
static int[] ne = new int[M];
......@@ -92,9 +108,9 @@ public class 区间 {
static ArrayDeque<Integer> q = new ArrayDeque<Integer>();
static void add(int a, int b, int c) {
e[count] = b;
w[count] = c;
ne[count] = h[a];
h[a] = count++;
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
}
......@@ -3,6 +3,8 @@
```
1:求不等式的可行解,
源点满足,从源点出发,一定可以走到所有的边
只有从源点出发能到达的边,才是满足不等式的
没考虑到那条边,就是没用到那条边,没满足某个不等式
2:求最大值或最小值
```
````
......@@ -34,29 +36,40 @@ Xi<=Xj+Ck
将不等式格式化,转化为j走到i长度为Ck的边
不一定走到所有点,但一定要能走到所有边,限制的是边
孤立的点也就是没有限制,
2:找到虚拟源点,使得虚拟源点可以到达所有的边
3:从源点求单源最短路
如果存在负环,说明不等式组无解!
如:X1->X2->X1 权值之和小于0
X2<=X1+C1
X1<=X2+C2
放缩X2<=X2+C2+C1
显然矛盾
X3<=X2+C2
X1<=X3+C3
放缩X2<=X3+c3+C2+C1
显然矛盾,原不等式组无解
不等式无解等价于图存在负环
如果没有负环,则dis[i]就是可行解
做一个对偶Xk>=Xi-Ck
i->连一条-Ck的边
dis[j]>=dis[i]+Ck求最长路
如果是求的最小值,求最长路,
如果求的是最长值,应该求最短路
如果是求的最小值,求最长路,求出每个变量X1,X2..的最小值
如果求的是最大值,应该求最短路 求出每个变量X1,X2..的最大值
应该有绝对关系,比如Xi>=0
转化Xi<=c c为常数,这类的不等式
如果没有无法求出最值,只能求出相对关系,把不等式组同时+d也满足
转化Xi<=c ,或者Xi>=c,c为常数,这类的不等式,如何变成边呢?
建立超级源点为X0到i长度是0的边
Xi<=C转化为Xi<=X0+C
构成不等式链对应路径,Xi<=Xj+C1<=Xk+C2+C1<=...<=X0+C1+C2...
放缩到最后变成,0+C1+C2+...上界
构成的不等式链求的是所有上界的最小值
Xi的最大值为一个所有上界的最小值等价于求0到i路径的最小值
以求最大值为例,所有从Xi出发,
构成不等式链 Xi<=Xj+C1<=Xk+C2+C1<=...<=C1+C2+C3+..最后一定是个常数
最终Xi的最大值为一个所有上界的最小值,,,等价于求0到i路径的最小值
每一个这样的不等式链,都是从0(超级源点)出发
\ No newline at end of file
......@@ -25,9 +25,31 @@ import java.util.Scanner;
* 2≤N≤1000,
* 1≤ML,MD≤104,
* 1≤L,D≤106
* 输入样例:
* 4 2 1
* 1 3 10
* 2 4 20
* 2 3 3
* 输出样例:
* 27
* 思路
* 不等式,并且使所有点联通,i<=i+1+0
* 加入i+1向i的边
* 题中求最大值,则用最短路,求出所有上界的最小值
* 首先关系先找全列出来:
* <p>
* 找出所有不等式
* 第一种关系:Xb-Xa<=L 转换后:Xb<=Xa+L ; 也就是 Xa—>Xb (权值为L)
* 第二种关系:Xb-Xa>=D 转换后:Xa<=Xb-D ; 也就是 Xb—>Xa (权值为D)
* 第三种关系:Xi<=X(i+1) 1<=i<n Xi<=X(i+1)+0
* 不存在超级源点,所以建立超级源点X0,假定所有的Xi都处于数轴右边
* 假定Xi<=X0 X0->Xi (权值为0) X0向所有边连长度为0的边
* 实现不用建立超级源点到所有点的边,因为第一步把超级源点放进队列,
* spfa就会把所有邻边都加进队列,所以直接加入队列并标记访问
* 把X1固定成0,然后看Xn是不是无限大,等价
* 有一个链式关系,但X1和Xn没有关系,所以没有任何限制,就是正无穷
* <p>
* 1.第一个问题,首先做一遍spfa判断一下有没有负环,此时可以假设虚拟源点为0;
* 2.然后再做一次spfa判断1到n的距离是否为正无穷;注意此时源点为1;
* 3.第三个问题,如果不满足以上两个条件则输出dis[n]即可;
*/
public class 排队布局 {
public static void main(String[] args) {
......@@ -37,6 +59,7 @@ public class 排队布局 {
int m2 = sc.nextInt();
for (int i = 1; i < n; i++) {
add(i + 1, i, 0);
//Xi<=X(i+1)
}
int a, b, c, t;
while (m1-- != 0) {
......@@ -49,6 +72,7 @@ public class 排队布局 {
a = t;
}
add(a, b, c);
//Xb<=Xa+L
}
while (m2-- != 0) {
a = sc.nextInt();
......@@ -60,10 +84,11 @@ public class 排队布局 {
a = t;
}
add(b, a, -c);
//Xb<=Xa-D
}
if (!spfa(n)) System.out.println(-1);
else {
spfa(1);
spfa(1);//从1开始往下找,看能不能找到n,看X1能否限制Xn,无法限制,则Xn最大正无穷
if (dis[n] == Integer.MAX_VALUE / 2) System.out.println(-2);
else System.out.println(dis[n]);
}
......@@ -74,6 +99,7 @@ public class 排队布局 {
Arrays.fill(st, false);
Arrays.fill(cnt, 0);
q.clear();
for (int i = 1; i <= size; i++) {
dis[i] = 0;
q.add(i);
......@@ -87,7 +113,7 @@ public class 排队布局 {
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 (cnt[j] >= n) return false;//判断是否存在负环!!!
if (!st[j]) {
q.add(j);
st[j] = true;
......
......@@ -38,6 +38,7 @@ import java.util.Scanner;
* 输出样例:
* 11
* 思路:
* 最小值->最长路
* 因为我们要求的是最小值且约束条件可转换为若干不等式,所以我们可以用差分约束来做,求最长路,不等式为大于号。
* 将题目转换成一堆不等式
* x=1=》A>=B&&B>=A
......@@ -63,17 +64,23 @@ public class 糖果 {
if (x == 1) {
add(b, a, 0);
add(a, b, 0);
//A>=B,B>=A
} else if (x == 2) {
add(a, b, 1);
//B>=A+1
} else if (x == 3) {
add(b, a, 0);
//A>=B
} else if (x == 4) {
add(b, a, 1);
//A>=B+1
} else add(a, b, 0);
//B>=A
}
for (int i = 1; i <= n; i++) {
add(0, i, 1);
}
}//所有的小朋友至少分到1个糖
if (!spfa()) System.out.println("-1");
else {
long res = 0;
......@@ -111,12 +118,12 @@ public class 糖果 {
static int finf = Integer.MIN_VALUE / 2;
static int n, m, N = 100010, M = 300010, count = 1;
static int n, m, N = 100010, M = 300010, count = 1;//最坏建3倍边,因为第一种双向边,每个点和超级源点的边
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 long[] dis = new long[N];
static int[] cnt = new int[N];
static boolean[] st = new boolean[N];
static ArrayDeque<Integer> q = new ArrayDeque<Integer>();
......
package graph.差分约束;
/**
* https://blog.csdn.net/weixin_45080867/article/details/108041493
* https://blog.csdn.net/qq_44828887/article/details/107291492
*
*/
public class 雇佣收银员 {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册