[学习笔记] 差分约束

一、差分约束

差分约束可以求解如下问题的一组解:

\[\begin{cases}x_{a_1} + c_1 \geq x_{b_1}\\ x_{a_2} + c_2 \geq x_{b_2} \\ \dots \\ x_{a_k} + c_k \geq x_{b_k}\end{cases} \]

其中 \(1 \leq a_i, b_i \leq n\)

我们发现这个很像求最短路的过程,即三角形不等式,所以我们从 \(a_i\)\(b_i\) 连一条长度为 \(c_i\) 的边。

然后跑最短路。跑完后的 \(dis\) 数组就是一组解。

如果有负环就是无解。

因为 \(c_i\) 不一定非负,所以使用 SPFA。

要求解最小应该要反着建边。

Template:https://www.luogu.com.cn/problem/P5960

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
int n, m, cnt, head[5005], dis[5005], isin[5005], que[5005];
struct Edge {
	int to, nxt, dis;
} ed[10005];
inline void add_edge (int u, int v, int w) {
	cnt ++;
	ed[cnt] = (Edge) {v, head[u], w};
	head[u] = cnt;
	return ;
}
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	read (n), read (m);
	for (int i = 1;i <= m; ++ i) {
		int u, v, w;
		read (u), read (v), read (w);
		add_edge (v, u, w);
	}
	for (int i = 1;i <= n; ++ i) add_edge (0, i, 0);
	for (int i = 1;i <= n; ++ i) dis[i] = 1073741819;
	dis[0] = 0;
	isin[0] = 1;
	queue < int > q;
	while (!q.empty ()) q.pop ();
	q.push (0);
	while (!q.empty ()) {
		int u = q.front (); q.pop ();
		isin[u] = 0, que[u] ++;
		if (que[u] > n + 1) {
			printf ("NO\n");
			return 0;
		}
		for (int i = head[u]; i ; i = ed[i].nxt) {
			int v = ed[i].to, w = ed[i].dis;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (!isin[v]) isin[v] = 1, q.push (v);
			}
		}
	}
	for (int i = 1;i <= n; ++ i) printf ("%d ", dis[i]);
	printf ("\n");
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

二、例题

洛谷 P1993 小 K 的农场

https://www.luogu.com.cn/problem/P1993

设第 \(i\) 个农场种植了 \(x_i\) 个单位的作物。

条件一

农场 \(a\) 比农场 \(b\) 至少多种植了 \(c\) 个单位的作物。

  • \(x_a - x_b \geq c (x_a - c \geq x_b)\)

转化为建图:

add_edge (a, b, -c);

条件二

农场 \(a\) 比农场 \(b\) 至多多种植了 \(c\) 个单位的作物。

  • \(x_a - x_b \leq c\)

转化一下:\(x_b - x_a \geq -c(x_b + c \geq x_a)\)

转化为建图:

add_edge (b, a, c);

条件三

农场 \(a\) 与农场 \(b\) 种植的作物数一样多。

那么就是 \(x_a + 0 \geq x_b, x_b + 0 \geq x_a\)

转化为建图:

add_edge (a, b, 0);
add_edge (b, a, 0);

然后就是跑 SPFA 判负环了,这个题不用输出方案,非常好。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
int n, m, cnt, head[5005], dis[5005], isin[5005], que[5005];
struct Edge {
	int to, nxt, dis;
} ed[15005];
inline void add_edge (int u, int v, int w) {
	cnt ++;
	ed[cnt] = (Edge) {v, head[u], w};
	head[u] = cnt;
	return ;
}
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	read (n), read (m);
	for (int i = 1;i <= m; ++ i) {
		int type;
		read (type);
		if (type == 1) {
			int a, b, c;
			read (a), read (b), read (c);
			add_edge (a, b, -c);
		}
		else if (type == 2) {
			int a, b, c;
			read (a), read (b), read (c);
			add_edge (b, a, c);
		}
		else {
			int a, b;
			read (a), read (b);
			add_edge (a, b, 0), add_edge (b, a, 0);
		}
	}
	for (int i = 1;i <= n; ++ i) add_edge (0, i, 0);
	for (int i = 1;i <= n; ++ i) dis[i] = 1073741819;
	dis[0] = 0;
	isin[0] = 1;
	queue < int > q;
	while (!q.empty ()) q.pop ();
	q.push (0);
	while (!q.empty ()) {
		int u = q.front (); q.pop ();
		isin[u] = 0, que[u] ++;
		if (que[u] > n + 1) {
			printf ("No\n");
			return 0;
		}
		for (int i = head[u]; i ; i = ed[i].nxt) {
			int v = ed[i].to, w = ed[i].dis;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (!isin[v]) isin[v] = 1, q.push (v);
			}
		}
	}
	printf ("Yes\n");
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

洛谷 P2474 [SCOI2008]天平

https://www.luogu.com.cn/problem/P2474

因为题目中只给出了大小关系,所以我们设:

  • \(mn_{i, j}\) 表示 \(w_i - w_j\) 的最小值。

  • \(mx_{i, j}\) 表示 \(w_i - w_j\) 的最大值。

其中 \(w_i\) 表示第 \(i\) 个砝码的重量。

初值

  • 若第 \(i\) 行第 \(j\) 列为 +,那么 \(mx_{i, j} = 2, mn_{i, j} = 1\)

  • 若第 \(i\) 行第 \(j\) 列为 -,那么 \(mx_{i, j} = -1, mn_{i, j} = -2\)

  • 若第 \(i\) 行第 \(j\) 列为 =,那么 \(mx_{i, j} = mn_{i, j} = 0\)

  • 若第 \(i\) 行第 \(j\) 列为 ?,那么 \(mx_{i, j} = 2, mn_{i, j} = -2\)

特别的,当 \(i = j\) 时,按 = 处理。

正确性显然。

转移方程

\[mn_{i, j} = \max\{mn_{i, k} + mn_{k, j}\} \]

\[mx_{i, j} = \min\{mn_{i, k} + mx_{k, j}\} \]

显然 \(w_i - w_j \leq mx_{i, j}\),找一个中介点 \(k\)

\[(w_i - w_k) + (w_k - w_j) \leq mx_{i, k} + mx_{k, j} \]

\[w_i - w_j \leq mx_{i, k} + mx_{k, j} \]

还要满足 \(w_i - w_j \leq mx_{i, j}\),所以是取 min,mn 数组的转移同理。

因为 \(n\) 只有 \(50\),所以我们可以跑 Floyd。

统计答案

1. \(w_A + w_B > w_C + w_D\)

\[w_A + w_B > w_C + w_D \]

\[w_A - w_C > w_D - w_B \]

因为一定要满足,所以 \(mn_{A, C} > mx_{D, B}\)

另一种:

\[w_A + w_B > w_C + w_D \]

\[w_B - w_C > w_D - w_A \]

因为一定要满足,所以 \(mn_{B, C} > mx_{D, A}\)

2. \(w_A + w_B = w_C + w_D\)

\[w_A + w_B = w_C + w_D \]

\[w_A - w_C = w_D - w_B \]

因为一定要满足,所以 \(mn_{A, C} = mx_{A, C} = mn_{D, B} = mx_{D, B}\)

另一种:

\[w_A + w_B = w_C + w_D \]

\[w_B - w_C = w_D - w_A \]

因为一定要满足,所以 \(mn_{B, C} = mx_{B, C} = mn_{D, A} = mx_{D, A}\)

3. \(w_A + w_B < w_C + w_D\)

\[w_A + w_B < w_C + w_D \]

\[w_A - w_C < w_D - w_B \]

因为一定要满足,所以 \(mx_{A, C} < mn_{D, B}\)

另一种:

\[w_A + w_B < w_C + w_D \]

\[w_B - w_C < w_D - w_A \]

因为一定要满足,所以 \(mx_{B, C} < mn_{D, A}\)

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
int n, A, B;
int mn[55][55], mx[55][55];
char s[55][55];
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	read (n), read (A), read (B);
	for (int i = 1;i <= n; ++ i) scanf ("%s", s[i] + 1);
	for (int i = 1;i <= n; ++ i) s[i][i] = '=';
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			if (s[i][j] == '+') mx[i][j] = 2, mn[i][j] = 1;
			if (s[i][j] == '-') mx[i][j] = -1, mn[i][j] = -2;
			if (s[i][j] == '=') mx[i][j] = mn[i][j] = 0;
			if (s[i][j] == '?') mx[i][j] = 2, mn[i][j] = -2;
		}
	}
	for (int k = 1;k <= n; ++ k) {
		for (int i = 1;i <= n; ++ i) {
			for (int j = 1;j <= n; ++ j) {
				if (i != j && i != k && k != j) {
					mx[i][j] = min (mx[i][j], mx[i][k] + mx[k][j]);
					mn[i][j] = max (mn[i][j], mn[i][k] + mn[k][j]);
				}
			}
		}
	}
	int ans1 = 0, ans2 = 0, ans3 = 0;
	for (int i = 1;i <= n; ++ i) {
		for (int j = i + 1;j <= n; ++ j) {
			if (i ^ A) ; else continue;
			if (j ^ A) ; else continue;
			if (i ^ B) ; else continue;
			if (j ^ B) ; else continue;
			ans1 += (mn[A][i] > mx[j][B] || mn[B][i] > mx[j][A]);
			ans2 += ((mn[A][i] == mx[A][i] && mn[j][B] == mx[j][B] && mn[A][i] == mn[j][B]) || ((mn[B][i] == mx[B][i] && mn[j][A] == mx[j][A] && mn[B][i] == mn[j][A])));
			ans3 += (mx[A][i] < mn[j][B] || mx[B][i] < mn[j][A]);
		}
	}
	printf ("%d %d %d\n", ans1, ans2, ans3);
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

洛谷 P4926 [1007] 倍杀测量者

https://www.luogu.com.cn/problem/P4926

转化一下问题,求最大的正实数 \(T\),使得以下不等式无解,若不存在合法的 \(T\) 就输出 \(-1\)

\(s_x\) 表示第 \(x\) 个选手的分数。

Flag type 1

“如果 X 没有 \(k-T\) 倍杀选手 Y,X 就女装。”

\[s_X \geq (k-T) s_Y \]

\[\frac{s_X}{s_Y} \geq k-T \]

\[\log_2(s_X) - \log_2(s_Y) \geq \log_2(k-T) \]

Flag type 2

“如果 X 选手 \(k+T\) 倍杀选手 Y,Y 就女装。”

\[s_X < (k+T)s_Y \]

\[\frac{s_X}{s_Y} < k + T \]

\[\log_2(s_X) - \log_2(s_Y) < \log_2(k + T) \]

处理初值

直接转化为 \(s_C - s_0 \geq x, s_C + s_0 \leq x\) 即可。

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
int n, s, t, cnt, head[1005], isin[1005], que[1005];
double dis[1005];
int o[1005], X[1005], Y[1005], k[1005];
int C[1005], val[1005];
struct Edge {
	int to, nxt;
	double dis;
} ed[10005];
inline void add_edge (int u, int v, double w) {
	cnt ++;
	ed[cnt] = (Edge) {v, head[u], w};
	head[u] = cnt;
	return ;
}
inline void cls () {
	for (int i = 0;i <= n; ++ i) head[i] = 0;
	cnt = 0;
}
inline bool SPFA () {
	for (int i = 1;i <= n; ++ i) dis[i] = 1073741819.0;
	for (int i = 1;i <= n; ++ i) isin[i] = 0;
	for (int i = 0;i <= n; ++ i) que[i] = 0;
	dis[0] = 0.0;
	isin[0] = 1;
	queue < int > q;
	while (!q.empty ()) q.pop ();
	q.push (0);
	while (!q.empty ()) {
		int u = q.front (); q.pop ();
		isin[u] = 0, que[u] ++;
		if (que[u] > n + 1) {
			return false;
		}
		for (int i = head[u]; i ; i = ed[i].nxt) {
			int v = ed[i].to;
			double w = ed[i].dis;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (!isin[v]) isin[v] = 1, q.push (v);
			}
		}
	}
	return true;
}
inline bool solve (double T) {
	cls (); 
	for (int i = 1;i <= s; ++ i) {
		if (o[i] == 1) {
			double K = k[i];
			K -= T;
			if (K < 1e-10) K = -1919810;
			else K = log2 (K);
			add_edge (X[i], Y[i], -K);
		}
		else {
			double K = k[i];
			K += T;
			K = log2 (K);
			add_edge (Y[i], X[i], K);
		}
	}
	for (int i = 1;i <= t; ++ i) {
		double W = log2 (val[i]);
		add_edge (C[i], 0, -W);
		add_edge (0, C[i], W);
	}
	return !SPFA ();
}
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	read (n), read (s), read (t);
	for (int i = 1;i <= s; ++ i) read (o[i]), read (X[i]), read (Y[i]), read (k[i]);
	for (int i = 1;i <= s; ++ i) {
		if (o[i] == 2) swap (X[i], Y[i]);
	}
	for (int i = 1;i <= t; ++ i) read (C[i]), read (val[i]);
	if (!solve (0)) printf ("-1\n");
	else {
		double L = 0, R = 10;
		while (R - L > 1e-5) {
			double mid = (L + R) / 2.0;
			if (solve (mid)) L = mid;
			else R = mid;
		} 
		if (solve (R)) printf ("%.8lf\n", R);
		else printf ("%.8lf\n", L);
	}
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/

洛谷 P5590 赛车游戏

https://www.luogu.com.cn/problem/P5590

\(d_i\) 表示 \(1\)\(i\) 的最短路。

对于每一条有向边 \((u, v)\),要保证 \(1\)\(n\) 的每一条路径长度相等,\((u, v)\) 的边权一定要是 \(d_v - d_u\)

特别的,如果 \((u, v)\) 不在任何一条 \(1\)\(n\) 的路径上,那么就可以随便标权值。

因为每一条边的边权在 \([1, 9]\) 之间,所以:

  • \(d_v - d_u \geq 1\) -> \(d_v - 1 \geq + d_u\)

  • \(d_v - d_u \leq 9\) -> \(d_u + 9 \geq + d_v\)

然后建图,跑差分约束,求出 \(d\),若有负环就无解。

\(1\) 不能到达 \(n\) 也是无解!

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
template < class Z >
inline void read (Z &tmp) {
	Z x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	tmp = !f ? x : -x;
}
int n, m, cnt, head[1005], dis[1005], isin[1005], que[1005];
struct Edge {
	int to, nxt, dis;
} ed[5005];
inline void add_edge (int u, int v, int w) {
	cnt ++;
	ed[cnt] = (Edge) {v, head[u], w};
	head[u] = cnt;
	return ;
}
int fir[2005], sec[2005], flag[2005], ok;
vector < int > gr[2005], fgr[2005];
int fst[1005], sct[1005];
inline void dfs (int u) {
	if (u == n) {
		fst[n] = 1;
		ok = 1;
		return ;
	}
	if (fst[u]) return ;
	fst[u] = 1;
	for (int v : gr[u]) {
		dfs (v);
	}	
}
inline void dfs2 (int u) {
	if (u == 1) {
		sct[1] = 1;
		return ;
	}
	if (sct[u]) return ;
	sct[u] = 1;
	for (int v : fgr[u]) {
		dfs2 (v);
	}
}
bool Memory_Ends;
signed main () {
	fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
	read (n), read (m);
	for (int i = 1;i <= m; ++ i) {
		read (fir[i]), read (sec[i]);
		gr[fir[i]].push_back (sec[i]);
		fgr[sec[i]].push_back (fir[i]);
	}
	dfs (1);
	dfs2 (n);
	if (!ok) {
		printf ("-1\n");
		return 0;
	}
	for (int i = 1;i <= m; ++ i) {
		if (fst[fir[i]] && sct[sec[i]]) flag[i] = 1;
	}
	for (int i = 1;i <= m; ++ i) {
		if (flag[i]) {
			add_edge (sec[i], fir[i], -1);
			add_edge (fir[i], sec[i], 9);
		}
	}
	for (int i = 1;i <= n; ++ i) add_edge (0, i, 0);
	for (int i = 1;i <= n; ++ i) dis[i] = 1073741819;
	dis[0] = 0;
	isin[0] = 1;
	queue < int > q;
	while (!q.empty ()) q.pop ();
	q.push (0);
	while (!q.empty ()) {
		int u = q.front (); q.pop ();
		isin[u] = 0, que[u] ++;
		if (que[u] > n + 1) {
			printf ("-1\n");
			return 0;
		}
		for (int i = head[u]; i ; i = ed[i].nxt) {
			int v = ed[i].to, w = ed[i].dis;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (!isin[v]) isin[v] = 1, q.push (v);
			}
		}
	}
	printf ("%d %d\n", n, m);
	for (int i = 1;i <= m; ++ i) {
		if (flag[i]) printf ("%d %d %d\n", fir[i], sec[i], dis[sec[i]] - dis[fir[i]]);
		else printf ("%d %d %d\n", fir[i], sec[i], 1);
	}
	fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
	return 0;
}
/*
Things to check:
1. int ? long long ? unsigned int ? unsigned long long ?
2. array size ? is it enough ?
*/
posted @ 2023-06-13 18:40  CountingGroup  阅读(8)  评论(0编辑  收藏  举报