/*Zjnu Stadium Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 0 Accepted Submission(s) : 0 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description In 12th Zhejiang College Students Games 2007, there was a new stadium built in Zhejiang Normal University. It was a modern stadium which could hold thousands of people. The audience Seats made a circle. The total number of columns were 300 numbered 1--300, counted clockwise, we assume the number of rows were infinite. These days, Busoniya want to hold a large-scale theatrical performance in this stadium. There will be N people go there numbered 1--N. Busoniya has Reserved several seats. To make it funny, he makes M requests for these seats: A B X, which means people numbered B must seat clockwise X distance from people numbered A. For example: A is in column 4th and X is 2, then B must in column 6th (6=4+2). Now your task is to judge weather the request is correct or not. The rule of your judgement is easy: when a new request has conflicts against the foregoing ones then we define it as incorrect, otherwise it is correct. Please find out all the incorrect requests and count them as R. Input There are many test cases: For every case: The first line has two integer N(1<=N<=50,000), M(0<=M<=100,000),separated by a space. Then M lines follow, each line has 3 integer A(1<=A<=N), B(1<=B<=N), X(0<=X<300) (A!=B), separated by a space. Output For every case: Output R, represents the number of incorrect request. Sample Input 10 10 1 2 150 3 4 200 1 5 270 2 6 200 6 5 80 4 7 150 8 9 100 4 8 50 1 7 100 9 2 100 Sample Output 2 Hint Hint: (PS: the 5th and 10th requests are incorrect) Source 2009 Multi-University Training Contest 14 - Host by ZJNU */ #include<stdio.h> int f[50010], dis[50010]; int find(int x) { if(x != f[x]) { int t = f[x];//wa f[x] = find(f[x]);//dis[x] += dis[f[x]];这里的dis[f[x]]有可能也是需要进一步更新的 dis[x] += dis[t];//f[x] = find[f[x]];所以必须先更新dis[f[x]]的值再加 } return f[x]; } int merge(int x, int y, int z) { int rx = find(x); int ry = find(y); if(rx != ry) { f[ry] = rx; dis[ry] = dis[x] + z - dis[y]; return 0; } else { if(dis[x] + z == dis[y]) return 0; else return 1; } } int main() { int i, j, k, n, m; while(scanf("%d%d", &n, &m) != EOF) { for(i = 0; i <= n; ++i) { dis[i] = 0; f[i] = i; } int a, b, c; j = 0; for(i = 0; i < m; ++i) { scanf("%d%d%d", &a, &b, &c); if(merge(a, b, c)) ++j; } printf("%d\n", j); } return 0; }
题意:有一个圆形的体育场,列数编号为1~300, 而行数假设为无穷大,现在有n个人入座,对于每个人的座位有一个条件A B x,即A的列数+ x = B的列数,现在给出m个此类的条件,按照给出条件的先后顺序,其中有一些条件会和前面已给出的条件相冲突,即某一个人的列数根据前面的条件已经确定,但后面给出的条件却与该列数不同则称为一个错误的条件,求给出的m个条件中有多少个错误的条件(注意:若多个人在同一列是允许的,因为行数是无限大的)。
思路:对于A和B来说一旦条件给出则A和B即可以看做是一个集合,并且B相对于A有一个距离,然而对于给出的m个条件,即检查各自的相对距离是否冲突,所以可以用并查集来处理集合问题,其次每次对于一个新的条件,若是同一个集合,则说明该点已经在前面被定过位置了,则开始检查该条件的相对距离是否和前面的相符号,若不是一个集合的,则保存相对距离,并将其归并与一个集合。
用dis数组存储每个点相对于其父节点的距离,这里主要有2种情况,即2个不同的集合的合并问题:当2个集合合并时要求出B的父节点到A的父节点的距离即 dis【RB】 = dis【A】+x - dis【B】;还有一个就是当两个集合合并后,由于父节点变更,所以后一个集合中的每一个点都要更新他们到父节点的距离,这部分可以在find函数中进行,只要没找到 父节点,则将该点的距离加入,直至找到父节点则和就是当前点到父节点的距离(这里需要注意的是必须先找后更新),因为对于途中找的点来说可能也是需要更新距离的,所以要先找将前面的点都更新了, 再回溯更新当前点。
体会:这道题可以帮助大家更深入的理解并查集的理解和运用~