点击打开链接http://acm.hdu.edu.cn/showproblem.php?pid=3047
1、题目大意:
有一个体育馆,座位呈环状,想象下,貌似体育馆都是这样的,每一列有300个座位,按逆时钟方向编号为1~300,假设行数无穷大。
某一天,有N个人(编号为1~N)来到这个体育馆看一场赛事,主办方提出了M个要求,要求的格式是"A B X",表示的是,假设A坐在编号为i的列,则B必须坐在编号为(i+x)的列上,这些要求里有一些是错误的,只有和前面的要求产生冲突时才算错误,其它都是正确的。程序要输出错误的要求个数。
分析:这是一道比较简单地并查集题目。
(1)弄清题意,找出出现冲突的位置,判断冲突很简单就是当两个人在同一行坐,同时他们到根节点的距离差值正好是他们之间的差值,此时就出现了冲突了。
(2)关键有两个地方,这也是并查集题目的难点,就是压缩集合,和求节点到根的距离。这里压缩集合就很简单了,一个通用的递归。求到跟的距离dist[a]+= dist[tem];dist[rb]=dist[a]+x-dist[b];注意这两行代码,这是核心代码,首先第一行是求出节点a到根的距离。第二行代码使用的是数学中向量计算的原理如图
2、题目:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 710 Accepted Submission(s): 293
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
2HintHint: (PS: the 5th and 10th requests are incorrect)
4、代码;
#include<stdio.h> int set[50005]; int dist[50005]; int count; /*find方法错误,待改正 int find(int x) { int r=x; while(r!=set[r]) {r=set[r]; dist[r]+=dist[set[r]]; } return r; }*/ int find(int a) { if(set[a]==a)return a; int tem = set[a]; set[a]=find( set[a]); dist[a] += dist[tem]; return set[a]; } void merge(int x,int y,int s) { int fx=find(x); int fy=find(y); if(fx!=fy) { set[fy]=fx; dist[fy]=dist[x]+s-dist[y]; } else { if(dist[y]-dist[x]!=s) count++; } } int main() { int n,m,a,b,c; while(scanf("%d%d",&n,&m)!=EOF) { count=0; for(int i=1;i<=n;i++) { set[i]=i; dist[i]=0; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); merge(a,b,c); } printf("%d\n",count); } return 0; } /* 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 */