蒟蒻学完并查集,看啥都是并查集。
于是我就神奇的用并查集解出了此题
思路就是从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;
}
撒花结束