『算法-ACM 竞赛』带权并查集–hdu3047 ZJnu stadiu
题意:给出一个 n,m,n 表示的是有 n 个人,m 表示的是 有 m 对关系: 接下来输入的就是这 m 对关系,a,b,x;表示的是 a,b 相距 x 个距离;然后判断输入的是否与这个数的上面的数信息一致, 输出不一致的数目;
思路:用一个 dist[ ]数组记录他到他的祖先的距离;然后对并查集合并的时候将 rb 的祖先赋给 ra,然后就要对 dist[rb]的值进行重新赋值,公式为 dist[ rb ] = dist[a] + x - dist[b],公式推导可以见下面这张图:
其中为了在找到他的祖先的的同时更新他们的各个 dist【】的值,运用了递归;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100000 + 10; ll dist[maxn]; ll n,m; ll father[maxn]; void Init() { for(int i = 1; i <= n ; i ++) { dist[i] = 0; father[i] = i; } } ll finds(ll x) { if(father[x] == x) return x; int t = father[x]; father[x] = finds(father[x]); dist[x] += dist[t]; return father[x]; } void unions(ll a,ll b,ll ra,ll rb,ll distance) { father[rb] = ra; dist[rb] = dist[a] + distance - dist[b]; } int main() { while( ~ scanf("%I64d%I64d",&n,&m) ) { Init(); ll ans = 0; for(int i = 1; i <= m ; i ++) { ll a,b,distance; scanf("%I64d%I64d%I64d",&a,&b,&distance); ll ra = finds(a); ll rb = finds(b); if(ra == rb) { if(dist[b] - dist[a] != distance) ans ++; } else unions(a,b,ra,rb,distance);
} printf("%I64d\n",ans); } return 0; }
|