浅说差分约束

差分约束

引入

当我们的题目中遇到一些存在不等关系的式子的时候,我们其实可以把它转换成图上问题来解决。为什么呢?我们可以观察一下这两个式子:

a j ≤ a i + w a_j\le a_i+w ajai+w

d i s j ≤ d i s i + w i , j dis_j\le dis_i+w_{i,j} disjdisi+wi,j

第一个是我们的要求的式子,第二个是我们在求最短路的时候的式子,是不是可以发现这两个是惊人的相似?那么我们是不是就可以类比一下?

我们把 a i a_i ai 类比成 d i s i dis_i disi a j a_j aj 类比成 d i s j dis_j disj ,然后我们在跑最短路的时候,一定是会处理出来所有点的 d i s dis dis 的,然而对于直接联通的两个点 i , j i,j i,j 和他们的最短路的值 d i s i , d i s j dis_i,dis_j disi,disj 是一定存在某种关系的,而这个关系就是上述的那个式子。

为什么呢?因为从 i i i j j j 的路径在最短路上要么是 w i , j w_{i,j} wi,j 要么就是从其他的地方转移了过去,并且这个距离一定是要比 w i , j w_{i,j} wi,j 要小的,要不然也转移不过去。因此, d i s j − d i s i dis_j-dis_i disjdisi 一定是小于等于 w i , j w_{i,j} wi,j 的(即 d i s j − d i s i ≤ w i , j dis_j-dis_i \le w_{i,j} disjdisiwi,j),那么左右移个项,就有了上面的那个式子。又因为我们求得了所有点的最短路,所以说每两个 d i s dis dis 之间是一定满足上面的这个要求的,那么类比后的 a j ≤ a i + w a_j\le a_i+w ajai+w 也就是一定可以成立的了。

同时,我们也不难注意到 a j − a i ≤ w    ⟺    a i − a j ≥ − w a_j-a_i\le w \iff a_i-a_j\ge -w ajaiwaiajw,所以说大于等于和小于等于是本质上是一样的。因此,在求解不等是的问题上,最短路和最长路都可以使用,两种方法并没有本质区别。

在一些题目中,如果说我们每次都从 1 号点出发,可能没有办法到达所有的点,如果是这样的话,我们的最短路也就求不了了,那么我们此时就要建立一个超级源点,使这个源点可以指向所有的点,那么我们从这个点出发,才可以到达其他的所有的点,至于这个点到其他点的边权,那就得看题目怎么要求了,下面会有例子

差分约束的连边方式

上文我们刚刚说了,可以将不等关系放到图上来做,但是呢,这个毕竟是图,怎么说也是有边权的,那么我们就要看看怎么建边了。

和上面同理,把 a i a_i ai 类比成 d i s i dis_i disi a j a_j aj 类比成 d i s j dis_j disj,基于上面的关系式,我们有证据可以在 i i i j j j 之间建一条长度为 w w w 的边,但是方向怎么确定呢?因为在移项后,是 d i s j − d i s i ≤ w i , j dis_j-dis_i \le w_{i,j} disjdisiwi,j 那么就说明 j j j i i i 之后出现,那么就说明这个边是从 i i i j j j 的。因此我们就可以这样的建一条边:

mp[i].push_back({j,w})

当我们每拿到一个不等式组的时候,我们就可以通过这种方法进行建边,又因为我们的 w w w 的值不一定是正数,所以说建完图后一般情况下是跑spfa,极少数情况会跑Dijkstra。

但是呢,上面的这种方法不一定是完全正确的,我们稍后会讲,在这之前,我们先把模板题给写了。

P5960 【模板】差分约束——洛谷

P5960 【模板】差分约束

题目描述

给出一组包含 m m m 个不等式,有 n n n 个未知数的形如:

{ x c 1 − x c 1 ′ ≤ y 1 x c 2 − x c 2 ′ ≤ y 2 ⋯ x c m − x c m ′ ≤ y m \begin{cases} x_{c_1}-x_{c'_1}\leq y_1 \\x_{c_2}-x_{c'_2} \leq y_2 \\ \cdots\\ x_{c_m} - x_{c'_m}\leq y_m\end{cases} xc1xc1y1xc2xc2y2xcmxcmym

的不等式组,求任意一组满足这个不等式组的解。

输入格式

第一行为两个正整数 n , m n,m n,m,代表未知数的数量和不等式的数量。

接下来 m m m 行,每行包含三个整数 c , c ′ , y c,c',y c,c,y,代表一个不等式 x c − x c ′ ≤ y x_c-x_{c'}\leq y xcxcy

输出格式

一行, n n n 个数,表示 x 1 , x 2 ⋯ x n x_1 , x_2 \cdots x_n x1,x2xn 的一组可行解,如果有多组解,请输出任意一组,无解请输出 NO

输入输出样例 #1

输入 #1

3 3
1 2 3
2 3 -2
1 3 1

输出 #1

5 3 5

说明/提示

样例解释

{ x 1 − x 2 ≤ 3 x 2 − x 3 ≤ − 2 x 1 − x 3 ≤ 1 \begin{cases}x_1-x_2\leq 3 \\ x_2 - x_3 \leq -2 \\ x_1 - x_3 \leq 1 \end{cases} x1x23x2x32x1x31

一种可行的方法是 x 1 = 5 , x 2 = 3 , x 3 = 5 x_1 = 5, x_2 = 3, x_3 = 5 x1=5,x2=3,x3=5

{ 5 − 3 = 2 ≤ 3 3 − 5 = − 2 ≤ − 2 5 − 5 = 0 ≤ 1 \begin{cases}5-3 = 2\leq 3 \\ 3 - 5 = -2 \leq -2 \\ 5 - 5 = 0\leq 1 \end{cases} 53=2335=2255=01

数据范围

对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 5 × 1 0 3 1\leq n,m \leq 5\times 10^3 1n,m5×103 − 1 0 4 ≤ y ≤ 1 0 4 -10^4\leq y\leq 10^4 104y104 1 ≤ c , c ′ ≤ n 1\leq c,c'\leq n 1c,cn c ≠ c ′ c \neq c' c=c

评分策略

你的答案符合该不等式组即可得分,请确保你的答案中的数据在 int 范围内。

如果并没有答案,而你的程序给出了答案,SPJ 会给出 There is no answer, but you gave it,结果为 WA;
如果并没有答案,而你的程序输出了 NO,SPJ 会给出 No answer,结果为 AC;

如果存在答案,而你的答案错误,SPJ 会给出 Wrong answer,结果为 WA;

如果存在答案,且你的答案正确,SPJ 会给出 The answer is correct,结果为 AC。

分析

这道题就是非常裸的模板题,按照刚刚上面讲的方法建边就可以了,因为是求合法的解,所以说最短路和最长路没有区别。顺便也把模板给你们写了。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e4+10,MAXN=1e8;
struct Node{
    int p,num;
};
vector<Node> mp[INF];
int n,m;
int dis[INF],used[INF],sum[INF];
void spfa(int x){//spfa模板

    queue<int> q;
    dis[x]=0,q.push(x),used[x]=1;
    while (!q.empty()){
        int u=q.front();q.pop();
        used[u]=0;
        int len=mp[u].size();
        for (int i=0;i<len;i++){
            int v=mp[u][i].p,w=mp[u][i].num;
            if (dis[v]>dis[u]+w){//最短路

                dis[v]=dis[u]+w;
                if (!used[v]){
                    if (++sum[v]>=n){//判断有没有负环,具体的之前讲过

                        cout<<"NO";
                        exit(0); 
                    }
                    q.push(v);
                    used[v]=1;
                }
            }
        }
    }
    for (int i=1;i<=n;i++){//输出答案

        cout<<dis[i]<<" ";
    }
    return;
}

void fi(){
    for (int i=0;i<=n;i++){
        dis[i]=MAXN;
    }
}
int main(){
    cin>>n>>m;
    fi();
    for (int i=1;i<=m;i++){
        int c1,c2,y;
        cin>>c1>>c2>>y;
        mp[c2].push_back({c1,y});//建边

    } 
    for (int i=1;i<=n;i++){
        mp[0].push_back({i,0});//建立超级源点

    }
    spfa(0);//从0开始跑spfa

    return 0;
}

差分约束中的极值问题

极值问题指的是,让我们求出一个满足某个性质的最优解。换句话说就是求某个事件的最大值或最小值(只是一个类比),比如说我们来看下面的这个例子:

假设我们现在要从 0 → 5 × 1 0 4 0 \rightarrow 5 \times 10^4 05×104 中选出尽量少的数,是每个区间 [ a i , b i ] [a_i,b_i] [ai,bi] 内部都有至少 c i c_i ci 个数被选出,我们要怎么做?

你非常敏锐的发现了如果用类似于前缀和的思想来做的话,有这样的一个不等关系式 p [ b i ] − p [ a i − 1 ] ≥ c i p[b_i]-p[a_i-1]\ge c_i p[bi]p[ai1]ci 转换一下就可以得到 p [ a i − 1 ] − p [ b i ] ≤ − c i p[a_i-1]-p[b_i]\le -c_i p[ai1]p[bi]ci

同时脑洞大开的你,又敏锐的发现了相邻两个数之间也存在一定的不等关系式

{ p [ b i + 1 ] − p [ b i ] ≤ 1 p [ b i ] − p [ b i + 1 ] ≤ 0 \begin{cases} p[b_{i+1}]-p[b_i]\le1 \\p[b_i]-p[b_{i+1}] \le0\end{cases} {p[bi+1]p[bi]1p[bi]p[bi+1]0

经过你一整严密的分析,发现没有其他的式子了,所以说就开始建边。

mp[bi].push_back({ai-1,-c});
mp[bi].push_back({bi+1,1});
mp[bi+1].push_back({bi,0});
//伪代码

然后你又发现,这道题好像不用建超级源点,所以说直接从最小的编号开始跑最短路,然后输出最大值的答案,这道题就做完了。

ACcode?
#include<bits/stdc++.h>
using namespace std;
const int INF=2e5+10,MAXN=1e8;
int maxn=-MAXN,minn=MAXN;

struct Node{
    int p,num;
};
vector<Node> mp[INF];
int used[INF],dis[INF];

void spfa(int x){
    queue<int> q;
    dis[x]=0,q.push(x),used[x]=1;
    while (!q.empty()){
        int u=q.front();q.pop();
        used[u]=0;
        for (auto v:mp[u]){
            if (dis[v.p]>dis[u]+v.num){
                dis[v.p]=dis[u]+v.num;
                if (!used[v.p]){
                    q.push(v.p);
                    used[v.p]=1;
                }
            }
        }
    }
}
void fi(){
    for (int i=minn;i<=maxn;i++){
        dis[i]=MAXN;
    }
}
int main(){
    int n;
    cin>>n;
    for (int i=1;i<=n;i++){
        int u,v,w;
        cin>>u>>v>>w;
        mp[v].push_back({u-1,-w});
        maxn=max(maxn,v),minn=min(minn,u-1);
    }
    fi();
    for (int i=minn;i<=maxn;i++){
        mp[i+1].push_back({i,0});
        mp[i].push_back({i+1,1});
    }
    spfa(minn);
    cout<<dis[maxn];
    return 0;
}

当你满怀信心的去测样例的时候,样例会让你直接寄掉。为什么,我们来看看这个样例

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

如果说,我们按照上述代码去做的话,最终的图长成这个样子

在这里插入图片描述

手画的长成这样。

在这里插入图片描述

真的非常的抽象。

同时如果我们从 0 开始跑最短路的话,就是会直通11点,把每个点都选上,然后这样的答案就是11.

这样肯定是不对的,为什么呢?因为最短路求得的是最大解,求得是极大值!

对于这个问题,其实网络上很多的博客都只是讲述了说什么,最大值用最短路,最小值用最长路,尽管这个结论是正确的,但是我们也要搞清楚为什么可以这样弄。所以说我们下面来证明一下:

对于最短路而言,他的不等关系式通常是 x i − x j ≤ a x_i - x_j \le a xixja,那么我们设当前有一条从 0 0 0 M M M 的最短路,其中经过了 v 1 , v 2 … v k v_1,v_2\dots v_k v1,v2vk 这些节点。

对于这些关系,我们原本的不等式为:

{ x v 1 − x 0 ≤ a 1 x v 2 − x v 1 ≤ a 2 … x M − x v k ≤ a k + 1 \begin{cases} x_{v_1}-x_0 \le a_1 \\x_{v_2}-x_{v_1}\le a_2 \\ \dots\\ x_M-x_{v_k}\le a_{k+1}\end{cases} xv1x0a1xv2xv1a2xMxvkak+1将左侧和右侧分别累加得到 x M − x 0 ≤ ∑ i = 1 k + 1 a i x_M-x_0\le\sum_{i=1}^{k+1}a_i xMx0i=1k+1ai

又因为这条最短路是确切经过了这些点的,所以说又有

{ d i s v 1 − d i s 0 = a 1 d i s v 2 − d i s v 1 = a 2 … d i s M − d i s v k = a k + 1 \begin{cases}dis_{v_1}-dis_0 =a_1\\dis_{v_2}-dis_{v_1}=a_2\\\dots\\dis_M-dis_{v_k}=a_{k+1}\end{cases} disv1dis0=a1disv2disv1=a2disMdisvk=ak+1这些式子累加后可以得到 d i s M − d i s 0 = ∑ i = 1 k + 1 a i dis_M-dis_0=\sum_{i=1}^{k+1}a_i disMdis0=i=1k+1ai

不难发现,第二个式子是第一个式子的上界,因此最短路求得的就是最大解。

对于最长路而言,他的不等关系式通常是 x i − x j ≥ a x_i - x_j \ge a xixja,那么我们设当前有一条从 0 0 0 M M M 的最短路,其中经过了 v 1 , v 2 … v k v_1,v_2\dots v_k v1,v2vk 这些节点。

对于这些关系,我们原本的不等式为:

{ x v 1 − x 0 ≥ a 1 x v 2 − x v 1 ≥ a 2 … x M − x v k ≥ a k + 1 \begin{cases} x_{v_1}-x_0 \ge a_1 \\x_{v_2}-x_{v_1}\ge a_2 \\ \dots\\ x_M-x_{v_k}\ge a_{k+1}\end{cases} xv1x0a1xv2xv1a2xMxvkak+1将左侧和右侧分别累加得到 x M − x 0 ≥ ∑ i = 1 k + 1 a i x_M-x_0\ge\sum_{i=1}^{k+1}a_i xMx0i=1k+1ai

又因为这条最短路是确切经过了这些点的,所以说又有

{ d i s v 1 − d i s 0 = a 1 d i s v 2 − d i s v 1 = a 2 … d i s M − d i s v k = a k + 1 \begin{cases}dis_{v_1}-dis_0 =a_1\\dis_{v_2}-dis_{v_1}=a_2\\\dots\\dis_M-dis_{v_k}=a_{k+1}\end{cases} disv1dis0=a1disv2disv1=a2disMdisvk=ak+1这些式子累加后可以得到 d i s M − d i s 0 = ∑ i = 1 k + 1 a i dis_M-dis_0=\sum_{i=1}^{k+1}a_i disMdis0=i=1k+1ai

不难发现,第二个式子是第一个式子的下界,因此最长路求得的就是最小解。

因此,我们在建边的时候,还要看一下题目中要我们求得是什么,是最大解还是最小解。就比如说上面的那个题,要我们求的就是“选出最少的数”,也就是最小解,那么我们现在就应该跑最长路,而最长路和最短路的建图方式又有一点不同,要反着建,所以说这就是我上面所说的“这个建图方法不一定是完全正确的”。

ACcode
#include<bits/stdc++.h>
using namespace std;
const int INF=2e5+10,MAXN=1e8;
int maxn=-MAXN,minn=MAXN;

struct Node{
	int p,num;
};
vector<Node> mp[INF];
int used[INF],dis[INF];

void spfa(int x){
	queue<int> q;
	dis[x]=0,q.push(x),used[x]=1;
	while (!q.empty()){
		int u=q.front();q.pop();
		used[u]=0;
		for (auto v:mp[u]){
			if (dis[v.p]<dis[u]+v.num){
				dis[v.p]=dis[u]+v.num;
				if (!used[v.p]){
					q.push(v.p);
					used[v.p]=1;
				}
			}
		}
	}
}
void fi(){
	for (int i=minn;i<=maxn;i++){
		dis[i]=-MAXN;
	}
}
int main(){
	int n;
	cin>>n;
	for (int i=1;i<=n;i++){
		int u,v,w;
		cin>>u>>v>>w;
		mp[u-1].push_back({v,w});//反着建
		maxn=max(maxn,v),minn=min(minn,u-1);
	}
	fi();
	for (int i=minn;i<=maxn;i++){//反着建
		mp[i].push_back({i+1,0});
		mp[i+1].push_back({i,-1});
	}
	spfa(minn);
	cout<<dis[maxn];
	return 0;
}

插一嘴题外话,这里其实还是可以跑最短路的,因为我们的终点和起点都只是单一点,而不是多对一或者是一对多,因此如果说我们建最短路的话,其实就是从终点跑回起点,然后取个相反数,这样的答案也是正确地。

为什么?原因很简单,对于一个有向图,如果说我们把所有边的方向都取反,同时也将所有权值也取反,那么我们最终的答案也是一定会取反的,这个是非常显然的,我们可以自己举个例子感受感受。

#include<bits/stdc++.h>
using namespace std;
const int INF=2e5+10,MAXN=1e8;
int maxn=-MAXN,minn=MAXN;

struct Node{
	int p,num;
};
vector<Node> mp[INF];
int used[INF],dis[INF];

void spfa(int x){
	queue<int> q;
	dis[x]=0,q.push(x),used[x]=1;
	while (!q.empty()){
		int u=q.front();q.pop();
		used[u]=0;
		for (auto v:mp[u]){
			if (dis[v.p]>dis[u]+v.num){
				dis[v.p]=dis[u]+v.num;
				if (!used[v.p]){
					q.push(v.p);
					used[v.p]=1;
				}
			}
		}
	}
}
void fi(){
	for (int i=minn;i<=maxn;i++){
		dis[i]=MAXN;
	}
}
int main(){
	int n;
	cin>>n;
	for (int i=1;i<=n;i++){
		int u,v,w;
		cin>>u>>v>>w;
		mp[v].push_back({u-1,-w});
		maxn=max(maxn,v),minn=min(minn,u-1);
	}
	fi();
	for (int i=minn;i<=maxn;i++){
		mp[i+1].push_back({i,0});
		mp[i].push_back({i+1,1});
	}
	spfa(maxn);
	cout<<abs(dis[minn]);
	return 0;
}

差分约束的小结

对于题目中含有不等关系式的题目,我们通常都可以转换成差分约束来做,但是呢就要注意一下题目中要我们求的东西,是最大值还是最小值,还是其他什么乱七八糟的值,但是都要抓住这个值来看。

如果是最小值,那么就跑最长路,同时将题目中的不等式改为 a j − a i ≥ w a_j-a_i\ge w ajaiw 的形式,然后从 i i i j j j 连长度为 w w w 的边。
如果是最大值,那么就跑最短路,同时将题目中的不等式改为 a i − a j ≤ w a_i-a_j\le w aiajw 的形式,然后从 j j j i i i 连长度为 w w w 的边。

例题感知

糖果——洛谷
这道题在洛谷上已经不能过了,因为被卡SPFA了,但仍然是一道非常经典的差分约束的题。

P3275 [SCOI2011] 糖果

题目描述

幼儿园里有 N N N 个小朋友, lxhgww \text{lxhgww} lxhgww 老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, lxhgww \text{lxhgww} lxhgww 需要满足小朋友们的 K K K 个要求。幼儿园的糖果总是有限的, lxhgww \text{lxhgww} lxhgww 想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入格式

输入的第一行是两个整数 N N N K K K。接下来 K K K 行,表示这些点需要满足的关系,每行 3 3 3 个数字, X X X A A A B B B

  • 如果 X = 1 X=1 X=1, 表示第 A A A 个小朋友分到的糖果必须和第 B B B 个小朋友分到的糖果一样多;
  • 如果 X = 2 X=2 X=2, 表示第 A A A 个小朋友分到的糖果必须少于第 B B B 个小朋友分到的糖果;
  • 如果 X = 3 X=3 X=3, 表示第 A A A 个小朋友分到的糖果必须不少于第 B B B 个小朋友分到的糖果;
  • 如果 X = 4 X=4 X=4, 表示第 A A A 个小朋友分到的糖果必须多于第 B B B 个小朋友分到的糖果;
  • 如果 X = 5 X=5 X=5, 表示第 A A A 个小朋友分到的糖果必须不多于第 B B B 个小朋友分到的糖果;

输出格式

输出一行,表示 lxhgww \text{lxhgww} lxhgww 老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 − 1 -1 1

输入输出样例 #1

输入 #1

5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1

输出 #1

11

说明/提示

对于 30 % 30\% 30% 的数据,保证 N ≤ 100 N\leq100 N100

对于 100 % 100\% 100% 的数据,保证 N ≤ 100000 N\leq100000 N100000

对于所有的数据,保证 K ≤ 100000 , 1 ≤ X ≤ 5 , 1 ≤ A , B ≤ N K\leq100000, 1\leq X\leq5, 1\leq A, B\leq N K100000,1X5,1A,BN

分析

根据题目,我们可以分析出来有这么几个关系式
{ x i = x j x i < x j x i ≥ x j x i > x j x i ≤ x j    ⟺    { x i − x j ≥ 0 且 x j − x i ≤ 0 x j − x i ≥ 1 x i − x j ≥ 0 x i − x j ≥ 1 x j − x i ≥ 0 \begin{cases} x_i=x_j\\x_i<x_j\\x_i\ge x_j\\x_i>x_j\\x_i\le x_j\end{cases} \iff \begin{cases} x_i-x_j \ge 0且x_j-x_i\le 0\\ x_j-x_i\ge 1\\x_i-x_j\ge0\\x_i-x_j\ge1\\x_j-x_i\ge0\end{cases} xi=xjxi<xjxixjxi>xjxixj xixj0xjxi0xjxi1xixj0xixj1xjxi0

再加上这道题求得是最小值,所以说跑最长路,并且把所有的不等式都整理成 a j − a i ≥ w a_j-a_i \ge w ajaiw,如上。然后建边。到这里都是非常简单的,接下来的超级源点就有意思了。我刚刚说了,超级源点到其他点的路径长是由确切的题目所定下来的,并不一定是0,那么这个地方就有变化了。题目中说了,要让每个小朋友都分到糖果,所以说这里超级源点向每个边连的值应该是1而不是0,这个是非常关键的。

同时这道题也是不能跑最短路的,因为这道题是一对多,如果说建成最短路的图的话,你就不知道应该从那个点出发了,除非说你再建一个超级源点,但是这样就太麻烦了。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e5+10;

struct Node{
	int v,w;
};
vector<Node> mp[INF];
int cnt[INF],dis[INF],used[INF];
int n,k;

void spfa(int x){
	memset(dis,-0x3f,sizeof(dis));
	queue<int> q;
	q.push(x),dis[x]=0,cnt[x]=1;
	while (!q.empty()){
		int u=q.front();q.pop();
		used[u]=0;
		int len=mp[u].size();
		for (int i=0;i<len;i++){
			int v=mp[u][i].v,w=mp[u][i].w;
			if (dis[v]<dis[u]+w){
				dis[v]=dis[u]+w;
				if (++cnt[v]>n){
					cout<<-1;
					return;
				}
				if (!used[v]){
					used[v]=1;
					q.push(v);
				}
			}
		}
	}
	long long tot=0;
	for (int i=1;i<=n;i++){
		tot+=dis[i];
	}
	cout<<tot;
}
int main(){
	cin>>n>>k;
	for (int i=1;i<=k;i++){
		int x,a,b;
		cin>>x>>a>>b;
		if (x==1){
			mp[a].push_back({b,0});
			mp[b].push_back({a,0});
		}else if (x==2){
			mp[a].push_back({b,1});
			if (a==b){
				cout<<-1;
				return 0;	
			}
		}else if (x==3){
			mp[b].push_back({a,0});
		}else if (x==4){
			mp[b].push_back({a,1});
			if (a==b){
				cout<<-1;
				return 0;
			}
		}else mp[a].push_back({b,0});
	}
	for (int i=1;i<=n;i++){
		mp[0].push_back({i,1});
	}
	spfa(0);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值