Hdu 6763 Total Eclipse 并查集+贪心

Hdu 6763 Total Eclipse 并查集+贪心

题目

Total Eclipse

题意

刚开始有一个联通的无向图,每个点都有自己的亮度,可以选择连通块,每次操作对连通块里面的点的亮度都进行减1,问最少要操作多少次才能都减为0.
(如果两点之间相隔着的点的亮度为0,视为这两点不连通)

题解

首先让所有点都不连通。用vector<> g记录连通情况。
我们先把所有权值加起来计算sum,然后给每个点按照权值从大到小排序,如果权值小的点和权值大的点应该是在一个连通块上,还没有连通起来的话,sum -= val,然后再将他们连通起来起来。最后就可以得出正确答案了。(PS:并查集需要使用路径压缩,不然会TLE)
爆破冠军。。。
在这里插入图片描述

AC代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
struct node
{
	ll v;
	int id;
} a[maxn];
vector<int> v[maxn];
int vis[maxn],pre[maxn];
int find(int x)
{
	if(x == pre[x]) return x;
	return pre[x] = find(pre[x]);
}
void merge(int x, int y)
{
	int fx = find(x), fy = find(y);
	if (fx != fy)
	{
		pre[fx] = fy;
	}
}
bool cmp(node x,node y)
{
	return x.v>y.v;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,m;
		ll sum=0;
		scanf("%d %d",&n,&m);
		for(int i=1; i<=n; i++)
		{
			scanf("%lld",&a[i].v);
			a[i].id=i;
			sum+=a[i].v;

			vis[i]=0;
			pre[i]=i;
			v[i].clear();
		}
		sort(a+1,a+n+1,cmp);
		while(m--)
		{
			int x,y;
			scanf("%d %d",&x,&y);
			v[x].push_back(y);
			v[y].push_back(x);
		}
		vis[a[1].id]=1;
		for(int i=2; i<=n; i++)
		{
			int id = a[i].id;
			int size = v[id].size();
			for(int j=0; j<size; j++)
			{
				int x = v[id][j];
				int fa,fb;
				if(vis[x]==1)
				{
					fa = find(x),fb = find(id);
					if(fa!=fb)
					{
						sum -= a[i].v;
						pre[fa] = fb;
					}
						
				}
			}
			vis[id]=1;
		}
		printf("%lld\n",sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911945/article/details/107765173