这题呢,还好吧,主要是在求相对坐标的时候,有点抽象,不过还是可以理解的,画个坐标对一对就知道了
还有就是,并查集的应用,因为要在某一个查询位置判定该点是否已经知道具体坐标,问题转化为俩点是否属于同一个集合,属于同一个集合,则相对于根节点的坐标都知道了,直接求曼哈顿距离,否则无法求出距离
代码中附带了解释:
#include<stdio.h>
#include<string.h>
#define MAXN 40010
int n,m,k;
struct node
{
int x,y,f;
}f[MAXN];
struct node1
{
int a,b,d;
char ch;
}e[MAXN];
int find(int x)
{
if(x==f[x].f)
return f[x].f;
int t=find(f[x].f);
f[x].x+=f[f[x].f].x;
f[x].y+=f[f[x].f].y;
f[x].f=t;
return f[x].f;
}//查找根节点,路径压缩,同时因为合并集合的时候,只是将某一个集合的根节点合并到另一个集合,即只修改了根节点的相对坐标
//所以查找根节点的过程,修改节点的相对坐标,注意体会这个递归的过程
void Union(int u,int v,int w,char c)
{
int a=find(u);
int b=find(v);
f[b].f=a;//将集合b并入集合a
int temp1=f[v].x,temp2=f[v].y;
switch(c)//这个比较好理解
{
case 'E': f[b].x=f[u].x+w;f[b].y=f[u].y;break;
case 'W': f[b].x=f[u].x-w;f[b].y=f[u].y;break;
case 'N': f[b].y=f[u].y+w;f[b].x=f[u].x;break;
case 'S': f[b].y=f[u].y-w;f[b].x=f[u].x;break;
}
f[b].x-=temp1;//求的是U 所在集合根节点相对于v的坐标
f[b].y-=temp2;
}
int abs(int a,int b)
{
if(a>b)
return a-b;
else return b-a;
}
int main()
{
int i,j,s,a,b;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
{
f[i].f=i;
f[i].x=f[i].y=0;
}
for(i=1;i<=m;i++)
{
getchar();
scanf("%d %d %d %c",&e[i].a,&e[i].b,&e[i].d,&e[i].ch);
}
s=0;
scanf("%d",&k);
while(k--)
{
scanf("%d %d %d",&a,&b,&j);
while(s<j)//这里因为查询位置是递增的,所以只要s比查询位置小,则继续合并
{
s++;
Union(e[s].a,e[s].b,e[s].d,e[s].ch);
}
if(find(a)!=find(b))//不在同一个集合,即某一个节点的具体坐标还不知道
printf("-1\n");
else
printf("%d\n",(abs(f[a].x,f[b].x)+abs(f[a].y,f[b].y)));//求曼哈顿距离
}
return 0;
}