设 xi
x
i
表示第 i
i
行 +1 和 −1
−
1
操作次数的差,yi
y
i
表示第 i
i
列 +1 和 −1
−
1
操作次数的差。
则对于每个限制 (i,j,c)
(
i
,
j
,
c
)
:xi+yj=c
x
i
+
y
j
=
c
。
即 xi+yj≥cANDxi+yj≤c
x
i
+
y
j
≥
c
A
N
D
x
i
+
y
j
≤
c
。
这似乎和一般的差分约束不一样,但可以改写成 xi−(−yi)≥cANDxi−(−yi)≤c
x
i
−
(
−
y
i
)
≥
c
A
N
D
x
i
−
(
−
y
i
)
≤
c
。
即 (−yi)−xi≤−cANDxi−(−yi)≤c
(
−
y
i
)
−
x
i
≤
−
c
A
N
D
x
i
−
(
−
y
i
)
≤
c
。
将对应行列的点连边,则判断存在性即为判断原图是否存在负环。
用 DFS_SPFA
D
F
S
_
S
P
F
A
实现即可。
Code
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>usingnamespacestd;
constint M = 2005;
int dis[M], T, n, m, K; bool vis[M];
struct Edge
{
int to, cst; Edge *nxt;
}p[M], *lst[M], *P = p;
inlinevoid Link(int x, int y, int z)
{
(++P)->nxt = lst[x]; lst[x] = P; P->to = y; P->cst = z;
}
inlineint get()
{
char ch; int res = 0; bool flag = false;
while (ch = getchar(), !isdigit(ch) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (ch = getchar(), isdigit(ch))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
inlinebool Dfs(int x)
{
vis[x] = true; int y;
for (Edge *e = lst[x]; e; e = e->nxt)
if (dis[y = e->to] > dis[x] + e->cst)
{
dis[y] = dis[x] + e->cst;
if (vis[y] || Dfs(y)) returntrue;
}
return vis[x] = false;
}
int main()
{
T = get();
while (T--)
{
memset(lst, NULL, sizeof(lst)); P = p;
n = get(); m = get(); K = get(); int x, y, c;
while (K--)
{
x = get(); y = get(); c = get();
Link(x, y + n, -c); Link(y + n, x, c);
}
memset(dis, 0, sizeof(dis));
memset(vis, false, sizeof(vis)); bool flag = false;
for (int i = 1, im = n + m; i <= im && !flag; ++i) flag |= Dfs(i);
puts(flag ? "No" : "Yes");
}
}