题解 luogu P2083 【找人】

蒟蒻学完并查集,看啥都是并查集。

于是我就神奇的用并查集解出了此题

思路就是从1至n*
m扫一圈,将当前房间所在位置与它指向房间merge注意必须把它merge到它指向房间的儿子节点。最后,你就会发现同学家正好是一个根节点

样例merge后样子如下,但样例中无死循环情况,这题是可能出现小明反复绕圈的情况的,所以我们要判定一下。

                2,3
             3,3   2,1
            1,2     1,3
           3,3       1,1
                   2,2  3,1

我们选取的存储方式为并查集中的 建立补集法 ,并查集数组中1至m为第一层,m+1至2*
m为第二层,以此类推,所以,并查集数组要有100000个

还有此题中切记不可用路径压缩,不然就无法完美重现找的过程。

代码如下

#include<bits/stdc++.h>
using namespace std;
int b[1005][100][3];
int bcj[99999999];
int hp=0,n,m,v,t=0,o=0;
void fget(int x)
{
    if (x/m!=bcj[x]/m)hp+=abs(bcj[x]/m-x/m)*v;
	if (bcj[x]==x)return;
	else fget(bcj[x]);//这里是重现找的部分,只比标准的找多一行家HP
}
int get(int x)
{
	o++;
	if (o>n*m) {o=0;return 2147483647;}//若进入了死循环,跳出
	if (bcj[x]==x){o=0;return x;}
	else return get(bcj[x]);	//并查集标准找的部分,注意没有路径压缩哦
}
void merge(int x,int y)
{
	bcj[x]=y;//不要连接到Y节点的树根部分要连接到最下面
}
int main()
{
	int i,j,x,y,ans=2147483647,k;
	cin>>n>>m>>v>>x>>y;
	for (i=1;i<=n*m;i++)bcj[i]=i;
	for (i=1;i<=n;i++)
	 for (j=1;j<=m;j++)
	 cin>>b[i][j][1]>>b[i][j][2];//每层用户的提供信息
	for (i=1;i<=n;i++)
	  for (j=1;j<=m;j++)
	  {
		  merge((i-1)*m+j,(b[i][j][1]-1)*m+b[i][j][2]);//合并部分,(i-1)*m+j为当前用户所在的i层第j间房,后面同理,不过是指向当前房间指向位置
	  }
	for (i=1;i<=m;i++)
	{
		if (get(i)==(x-1)*m+y)
		{fget(i);if (hp<ans)ans=hp;hp=0;}//若根节点为同学家,找,替换最小值
	}
	if (ans==2147483647)cout<<"impossible";
	else cout<<ans;//输出
	return 0;
}

撒花结束

猜你喜欢

转载自blog.csdn.net/qq_39441542/article/details/84675103