题目链接:http://poj.org/problem?id=1984
F1 --- (13) ---- F6 --- (9) ----- F3 | | (3) | | (7) F4 --- (20) -------- F2 | | | (2) F5 | F7
* Line 1: Two space-separated integers: N and M * Lines 2..M+1: Each line contains four space-separated entities, F1, F2, L, and D that describe a road. F1 and F2 are numbers of two farms connected by a road, L is its length, and D is a character that is either 'N', 'E', 'S', or 'W' giving the direction of the road from F1 to F2. * Line M+2: A single integer, K (1 <= K <= 10,000), the number of FB's queries * Lines M+3..M+K+2: Each line corresponds to a query from Farmer Bob and contains three space-separated integers: F1, F2, and I. F1 and F2 are numbers of the two farms in the query and I is the index (1 <= I <= M) in the data after which Bob asks the query. Data index 1 is on line 2 of the input data, and so on.
* Lines 1..K: One integer per line, the response to each of Bob's queries. Each line should contain either a distance measurement or -1, if it is impossible to determine the appropriate distance.
7 6 1 6 13 E 6 3 9 E 3 5 7 S 4 1 3 N 2 4 20 W 4 7 2 S 3 1 6 1 1 4 3 2 6 6Sample Output
13 -1 10Hint
这题用了两天时间去思考,同时在刚写代码的时候参考了https://www.cnblogs.com/kuangbin/archive/2013/04/05/3000475.html的代码,感谢!
A有n个农场,农场之间有m条路,之后输入f1,f2,L,d,农场编号、距离、方向(之后称为第一组数据输入)。注意到这里的方向都是垂直或者水平的,所以后面在记录坐标的时候只需要改变x/y一个方向的就好。之后B问了k个问题,输入数据(之后称为第二组数据)f1,f2,是农场编号,I意思在在A数据输入的第I行知不知道f1,f2之间的距离,这里距离题目也给了定义是|x1-x2|+|y1-y2|,如果可以知道则输出距离,不知道就输出-1。以下给出逐步解题的思考过程。
在第一次写这个题目的时候第一个感觉是混乱,没有一个明确的思路,数据结构怎么用也不明晰。只有逐步写下去了。第一组数据输入的时候首先要记录下这个图的信息,建立数组f1,f2,L,和 char 数组d存储。之后可以想到在输出最后距离的时候判断是否输出-1,就要用并查集分组,如果在一组可以得到距离则输出距离。因此需要pre[],并查集,并初始化pre[i]=i;.B问了k个问题,要把他们当做一个一个的问题处理,用一个node记录信息除了x,y,I之外,还需要记录id表示顺序,以便在输出时按id顺序输出答案。至此,所需数据结构基本搭建完。
核心解题:在将所有输入数据获取完毕后
step1:首先要将问题按照I的大小排序,小的在前面,使用sort和cmp函数。
step2:之后一个一个处理k个问题(for循环)。处理一个问题就需要把第一组数据拿来建图获得答案,并且这个问题的I有多大就到第一组数据的第几行,处理第一组数据时从第一行开始,用t标记。寻找第t组数据的两个农场的根节点。
重点:不能写成dx[x]+=dx[temp],因为temp永远是这个节点的最终的根节点,而pre【x】只是当前这个节点最近的一个根节点,而距离的更改需要根据离当前节点的最近的那个节点去修改。
step4:距离更新
如果两个根节点不一样则需要合并,永远把第一个农场作为第二个农场的根节点。重点写一下距离如何更新
dy[t2] = dy[f1[t]] - dy[f2[t]] + l[t];
因为这个时候t2已经变成以t1为根节点了,那么自然坐标要改变,首先回到子节点f2[t]的坐标,所以 - dy[f2[t]],再从f2[t]走到f1[t],这里根据(WSEN跟新),然后再从f1[t]走到t1,即f1[t]与它根节点的距离即+ dy[f1[t]]。
最后输出答案。
总的来说,这题值得好好体会思考!
附代码:
#include
#include
#include
using namespace std;
const int maxn = 40010;
int f1[maxn], f2[maxn], l[maxn];
int pre[maxn];
int dx[maxn], dy[maxn];
char d[maxn][3];
struct Node {
int x;
int y;
int I;
int id;
};
Node node[maxn];
int ans[maxn];
bool cmp(Node a,Node b)
{
return a.I < b.I; //输入的第几行不一定就是默认的升序,可能是乱序的需要我们排序
}
int find(int x)
{
if(x==pre[x])
{
return x;
}
int temp = find(pre[x]);
//dx【x】是x的坐标,要相对于不同的根节点更新
//路劲压缩
dx[x] += dx[pre[x]]; //错误原因。。。写成了dx[x]+=dx[x]+dx[pre[x]];
dy[x] += dy[pre[x]]; //不能写dx+=dx[temp]!!!!!!!!!!
return pre[x]=temp;
}
int main()
{
int n, m,k;
cin >> n >> m; //n个农场,m个路
//init
for (int i = 1; i <= n; i++)
{
pre[i] = i;
}
memset(dx, 0, sizeof(dx));
memset(dy, 0, sizeof(dy));
for (int i = 1; i <= m; i++)
{
cin >> f1[i] >> f2[i] >> l[i] >> d[i];
}
cin >> k;
for (int i = 0; i < k; i++) //x是第一个农场,y是第二个,不是坐标
{
cin >> node[i].x >> node[i].y >> node[i].I;
node[i].id = i;
}
sort(node , node + k , cmp);
//进行数据处理,根据问的问题进行
int t = 1; //用于从第一部分输入的第一个元素开始处理坐标值
for (int i = 0; i < k; i++) //处理的是问题输入部分
{
//在把问题输入一行的结果得出后,才会进入下一行,而在这个处理这一行时要得出答案,遍历所有while中条件
while (t <= m&&node[i].I >= t)//只有I标记大于tt时候说明需要知道之前的所有路径
{
int t1 = find(f1[t]), t2 = find(f2[t]);
if (t1 != t2) //根节点不一样,需要更新操作,总是把前面的作为根节点
{
pre[t2] = t1;
if (d[t][0] == 'N') //yu坐标改变,+
{
dy[t2] = dy[f1[t]] - dy[f2[t]] + l[t]; //根节点t2的坐标
dx[t2] = dx[f1[t]] - dx[f2[t]];
}
else if (d[t][0] == 'S')
{
dy[t2] = dy[f1[t]] - dy[f2[t]] - l[t];
dx[t2] = dx[f1[t]] - dx[f2[t]];
}
else if (d[t][0] == 'E')
{
dx[t2] = dx[f1[t]] - dx[f2[t]] + l[t];
dy[t2] = dy[f1[t]] - dy[f2[t]];
}
else if (d[t][0] == 'W') // f1 在 f2 的左边
{
dx[t2] = dx[f1[t]] - dx[f2[t]] - l[t];
dy[t2] = dy[f1[t]] - dy[f2[t]];
}
}
t++;
}//while结束,在第t列第一部分数据的情况下,将各个点坐标值更新
//输出结果
if (find(node[i].x) != find(node[i].y))ans[node[i].id] = -1;
else
{
ans[node[i].id]= abs(dx[node[i].x] - dx[node[i].y]) + abs(dy[node[i].x] - dy[node[i].y]); //node中的xy代表田地的编号!!!!!
}
}
for (int i = 0; i < k; i++)
{
cout << ans[i] << endl;
}
return 0;
}
勇往直前,自我管理,怀着一颗奋斗的心,永不退怯!