【题解】洛谷 P2294 [HNOI2005] 狡猾的商人(带权并查集)

实际上运用带权并查集的模板可以很好地解决这个问题。。

注意并查集应从0-n初始化,我们把第i月和第0个月的差值设为num[i],并且初始化为0。find函数进行并查集寻找父亲的操作,只不过在这个过程中,要更新num[x]。若二者有父亲结点不同,就更新父亲结点,并更新num数组(例如我是把f2接到f1上,假设f2比f1大z,那么可以得到更新后num[y]+num[f2]=num[x]+z,移项可表示num[f2])。如果二者父亲相同 就需要判断账目是否为真了,由于我假定是后面的月份和前面的月份作差,就只需要比较num[y]-num[x]!=z即可,注意用标记来记录真假情况。带权并查集比较绕,要明白自己写的x和y是什么含义、谁是父亲,这样能作差得到正确的结果。我一开始把判断是否为相同父亲的情况写到一个合并函数里,结果就找完父亲后又判断了一遍。。两者应当是if-else的关系,以后别搞混了。。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=110;
const int maxm=1010;
int n,m,w;
int fa[maxn],num[maxn];
int find(int x)
{
	if(fa[x]==x) return x;
	int t=fa[x];
	fa[x]=find(fa[x]);
	num[x]+=num[t];
	return fa[x];
}
int main()
{
	cin>>w;
	while(w--)
	{
		cin>>n>>m;
		for(int i=0;i<=n;i++)
		{
			fa[i]=i;
			num[i]=0;
		}
		bool bb=true;
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			cin>>x>>y>>z;
			x--;
			int f1=find(x),f2=find(y);
			if(f1!=f2)
			{
				fa[f2]=f1;
				num[f2]=num[x]-num[y]+z;
			}
			else if(num[y]-num[x]!=z)
			{
				bb=false;
			}
		//	cout<<num[y]<<' '<<num[x]<<endl;
		}
		
		if(bb==true) cout<<"true"<<endl;
		else cout<<"false"<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/rem_inory/article/details/81154237