HDU3047Zjnu Stadium(并查集)

来源:互联网 发布:淘宝店铺严重违规12分 编辑:程序博客网 时间:2024/06/06 10:51

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)
题目大意:
有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这m个关系之间有多少个错误,所谓错误就是当前这个关系与之前的有冲突。

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100000 + 10;int  dist[maxn];int n,m;int  par[maxn];void init(){    for(int i = 1; i <= n ; i ++)    {        dist[i] = 0;       par[i] = i;    }}int finds(int x){    if(par[x] == x)        return x;    int  t = par[x];    par[x] = finds(par[x]);    dist[x] += dist[t];    return par[x];}void unions(int a,int b,int ra,int rb,int distance){    par[rb] = ra;    dist[rb] = dist[a] + distance - dist[b];}int main(){    while( ~ scanf("%d%d",&n,&m) )    {        init();        int ans = 0;        for(int i = 1; i <= m ; i ++)        {            int a,b,distance;            scanf("%d%d%d",&a,&b,&distance);            int ra = finds(a);            int rb = finds(b);            if(ra == rb)            {                if(dist[b] - dist[a] != distance)                    ans ++;            }            else unions(a,b,ra,rb,distance);        }        printf("%d\n",ans);    }    return 0;}#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100000 + 10;int  dist[maxn];///来记录每个点到它祖先的距离int n,m;int  par[maxn];void init(){    for(int i = 1; i <= n ; i ++)    {        dist[i] = 0;       par[i] = i;    }}int finds(int x){    if(par[x] == x)        return x;    int  t = par[x];    par[x] = finds(par[x]);    dist[x] += dist[t];///dis[x]+=父亲节点到根的距离 。这样就是X到根的距离     return par[x];///每次返回都是同一个数 ,即这个集合的根}bool unions(int a,int b,int distance){    int ra = finds(a);//找各自的根节点即a->ra    int rb = finds(b);//找各自的根节点 b->rb     if(ra == rb )  ///祖先相同找 距离 要是距离不是给的数据说明是错误的     {         if(dist[b] - dist[a] != distance)        return 1;         return 0;     }     else     {          par[rb] = ra;///合并集合          dist[rb] = dist[a] - dist[b] + distance;///更新距离          return 0;     }}int main(){    while( ~ scanf("%d%d",&n,&m) )    {        init();        int ans = 0;        for(int i = 1; i <= m ; i ++)        {            int a,b,distance;            scanf("%d%d%d",&a,&b,&distance);                    if(unions(a,b,distance)) ans ++;        }        printf("%d\n",ans);    }    return 0;}

分析如下:先将各个点对unions起来得到如下图解:
这里写图片描述
这里写图片描述

有此得到精髓的向量公式:
这里写图片描述

每合并一个根节点都需要更新权值,更新路径。

原创粉丝点击