1. 程式人生 > 實用技巧 >bzoj 4500 矩陣

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。