您的位置:首页 > 产品设计 > UI/UE

HDU - 4424 Conquer a New Region 思维+并查集启发式合并

2017-09-30 22:57 489 查看
题目链接

题意:

给n个城镇,然后每两个城镇的价值给出,但是u->v的价值是u->v这条路径上的最小值,问从任意一个点出发到其他位置的和的最大值

思路:

很好的一个并查集题目,和队友想了一会才想出来.说实话这个并查集不是很好想。

因为这个题目是路径上的最小值为sij,所以我们要将边的权值从大到小排序,这样在用并查集维护两堆合并的最优值时,假设祖先分别为f1和f2,首先内部我们已经处理好了(每次合并就已经处理好),因为从大到小排序的,那么我们现在维护的这条边一定是当前最小的,那么我们以祖先f1到另一堆的所有点的sij即为当前这条边的cij,而到自己这一堆我们的已经处理好了为sum[f1]。(以f2同理)

关键是合并的时候怎么合并,因为要求和的最大值,所以这里我们用num[i]表示该堆的点的个数,sum[i]表示该堆,以i为选定的点,到本堆其他点的和的最大值是多少,合并时 f1,f2两堆,如果num[f2]*w+sum[f1]大,则新堆以f1为选定点,如果num[f1]*w+sum[f2]大则合并到f2上,这个过程中维护一个最大值即可》

#include<bits/stdc++.h>

using namespace std;
const int maxn = 2e5+5;
typedef long long ll;
int n;
int pre[maxn],num[maxn];
ll sum[maxn],ans;
void init()
{
for(int i = 0;i <= n;++i)
pre[i] = i,sum[i] = 0,num[i] = 1;
}
struct node
{
int u,v,w;
bool operator<(const node & z) const
{
return w > z.w;
}
}a[maxn];
int find(int x)
{
return x == pre[x] ? x : pre[x] = find(pre[x]);
}
void join(int x,int y,int w)
{
int f1 = find(x),f2 = find(y);
ll s1 = sum[f1] + (ll) w * num[f2];
ll s2 = sum[f2] + (ll) w * num[f1];
if(s1 >= s2)
{
pre[f2] = f1;
sum[f1] = s1;
num[f1] += num[f2];
}
else
{
pre[f1] = f2;
sum[f2] = s2;
num[f2] += num[f1];
}
ans = max(ans,max(sum[f1],sum[f2]));
return ;
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i = 1;i < n;++i)
scanf("%d %d %d",&a[i].u,&a[i].v,&a[i].w);
sort(a+1,a+n);
ans = 0;
for(int i = 1;i < n;++i)
{
join(a[i].u,a[i].v,a[i].w);
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: