了解了种类并查集,同时还知道了一个小技巧,这道题就比较容易了。
其实这是我碰到的第一道种类并查集,实在不会,只好看着别人的代码写。最后半懂不懂的写完了。然后又和别人的代码进行比较,还是不懂,但还是交了。
现在回过头来看,又看了一遍。
题意——
输入——
给出多组测试数据。
每组数据第一行包含两个整数n, m。n表示共有1——n这么多个数,m表示m组提示。
接下来m行,每行包含三个整数a, b, val。表示从a到b这几个数的和为val。
这几组数有可能有冲突,问一共有多少组有冲突的数据。
输出——
输出有冲突的数据的数量。
举例——
10 5
1 10 100
7 10 28
1 3 21
4 6 41
6 6 1
其中前三组数据明确4——6几个数的和为40,而第四组数据表示4——6几个数的和为41,那么这一组数据就是有冲突的。所以这组测试数据的输出为1。
那么分种类就行了。这里其实种类并不明显,或者说并不是标准的种类,只是算法设计上借鉴了种类并查集的思想(也可能是我对这个还不太理解)。这里使用了一个数组来存储n个数之间的相对关系(即a到b的和)。
假如a到b的和为val,a当前所存的值为x,那么b的值修改为x+val,如果b的值已经有了,且!=x+val,那么冲突数+1。
一个小技巧——
除此之外,还有一点需要注意,1——7和7——10不能直接按照1——10进行合并。如果是1——6和7——10,那么可以合并为1——10。所以,我采取的方法是使用a-1和b进行合并。即将1——6看做0——6,将7——10看做6——10,所以合并出来就是0——10。
种类并查集:hdu1829—— http://www.cnblogs.com/mypride/p/4743357.html
小技巧:hdu3461—— http://www.cnblogs.com/mypride/p/4671926.html
上代码——
1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int N = 200010; 9 const int M = 40010; 10 11 int sum[N], fm[N]; //sum[]数组表示任意区间内的数的相对的和。 12 int n, m; 13 int x, y, val; 14 int ans; 15 16 int mfind(int x) 17 { 18 if(x == fm[x]) return x; 19 int fx = fm[x]; 20 fm[x] = mfind(fm[x]); 21 sum[x] += sum[fx]; //及时修改sum[]数组,即,第x个数到当前根节点之间的差值(或者说和)。 22 return fm[x]; 23 } 24 25 void mmerge(int x, int y, int val) 26 { 27 int fx = mfind(x); 28 int fy = mfind(y); 29 if(fx == fy) 30 { 31 if(sum[y]-sum[x] != val) ans++; 32 } 33 else 34 { 35 fm[fy] = fx; 36 sum[fy] = sum[x]-sum[y]+val; //及时修改sum[]数组,即,两个根节点之间的差值(或者说和)。 37 } 38 //for(int i = 0; i <= n; i++) printf("%4d", sum[i]); 39 //printf(" "); 40 } 41 42 void init() 43 { 44 for(int i = 0; i <= n; i++) 45 { 46 sum[i] = 0; //初始化差值 47 fm[i] = i; 48 } 49 ans = 0; 50 for(int i = 0; i < m; i++) 51 { 52 scanf("%d%d%d", &x, &y, &val); 53 mmerge(x-1, y, val); 54 } 55 } 56 57 int main() 58 { 59 //freopen("test.in", "r", stdin); 60 while(~scanf("%d%d", &n, &m)) 61 { 62 init(); 63 printf("%d ", ans); 64 } 65 return 0; 66 }