题目描述
有一个n*m的矩阵,初始每个格子的权值都为0,可以对矩阵执行两种操作:
1. 选择一行, 该行每个格子的权值加1或减1。
2. 选择一列, 该列每个格子的权值加1或减1。
现在有K个限制,每个限制为一个三元组(x,y,c),代表格子(x,y)权值等于c。问是否存在一个操作序列,使得操作完后的矩阵满足所有的限制。如果存在输出”Yes”,否则输出”No”。
输入
先输入一个T(T <= 5)代表输入有T组数据,每组数据格式为:
第一行三个整数n, m, k (1 <= n, m,k <= 1000)。
接下来k行,每行三个整数x, y, c。
输出
对于每组数据,输出Yes或者No。
样例输入
2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 1
样例输出
Yes
No
题解
带权并查集
如果把行操作看作加,列操作看作减,那么每个限制就是“某行操作比某列操作大多少”。
使用带权并查集维护即可。
注意多组数据要把数据读全。
#include <queue> #include <cstdio> #include <cstring> #define N 1010 using namespace std; int x[N] , y[N] , z[N] , f[N << 1] , r[N << 1]; int find(int x) { if(x == f[x]) return x; int t = f[x]; f[x] = find(t) , r[x] += r[t]; return f[x]; } int main() { int T; scanf("%d" , &T); while(T -- ) { int n , m , k , i , tx , ty; scanf("%d%d%d" , &n , &m , &k); for(i = 1 ; i <= k ; i ++ ) scanf("%d%d%d" , &x[i] , &y[i] , &z[i]) , y[i] += n; for(i = 1 ; i <= n + m ; i ++ ) f[i] = i , r[i] = 0; for(i = 1 ; i <= k ; i ++ ) { tx = find(x[i]) , ty = find(y[i]); if(tx != ty) f[tx] = ty , r[tx] = z[i] + r[y[i]] - r[x[i]]; else if(r[x[i]] - r[y[i]] != z[i]) break; } if(i > k) puts("Yes"); else puts("No"); } return 0; }