bzoj 4500 矩阵

链接

我们可以把行操作看成加一,把列操作看成减一。

假如,有一个限制条件是 \(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。

posted @ 2020-08-13 21:32  genshy  阅读(91)  评论(0编辑  收藏  举报