我们可以把行操作看成加一,把列操作看成减一。
假如,有一个限制条件是 \(C[i][j] = z\)
我们可以把它看成 \(d[i] - d[j] = z\);
这样,我们就可以用带权并查集来维护,判断是否发生冲突就解决了。
当合并时 \(d[fx] = z - d[i] + d[j]\)
我们可以推一下这个式子 ,我们把上面那个移项就会变成 \(z-d[j]+d[i]\)
这样直接合并就行了
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int T,n,m,k,flag;
int fa[2010],d[2010],x[1010],y[1010],z[1010];
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s= s * 10+ch - '0'; ch = getchar();}
return s * w;
}
int find(int x)//边带权并查集
{
if(fa[x] == x) return x;
int root = find(fa[x]);
d[x] += d[fa[x]];
return fa[x] = root;
}
int main()
{
T = read();
while(T--)
{
n = read(); m = read(); k = read(); flag = 0;
for(int i = 1; i <= n; i++) fa[i] = i,d[i] = 0;
for(int i = 1; i <= m; i++) fa[i+n] = n+i,d[n+i] = 0;
for(int i = 1; i <= k; i++) x[i] = read(), y[i] = read() + n, z[i] = read();//要读完一组数据
for(int i = 1; i <= k; i++)
{
int xx = find(x[i]), yy = find(y[i]);
if(xx != yy)//如果不在一个集合就合并
{
fa[xx] = yy;
d[xx] = z[i] - d[x[i]] + d[y[i]];
}
else
{
if(d[x[i]] - d[y[i]] != z[i]) flag = 1;//在一个集合判断是否冲突
}
}
if(flag == 1) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}
有个问题。,就是不能把列看成加,把行看成减来做。但这样就会出错
这个问题,很奇怪,我也不知道为什么QAQ。