2271: 魔法交流活动

问题 E: 魔法交流活动

时间限制: 1 Sec   内存限制: 128 MB
提交: 177   解决: 56
[ 提交][ 状态][ 讨论版][命题人: admin]

题目描述

魔法学校近日开展了主题为“天气晴朗”的魔法交流活动。
N名魔法师按阵法站好,之后选取N - 1条魔法链将所有魔法师的魔力连接起来,形成一个魔法阵。
魔法链是做法成功与否的关键。每一条魔法链都有一个魔力值V,魔法最终的效果取决于阵中所有魔法链的魔力值的和。
由于逆天改命的魔法过于暴力,所以我们要求阵中的魔法链的魔力值最大值尽可能的小,与此同时,魔力值之和要尽可能的大。
现在给定魔法师人数N,魔法链数目M。求此魔法阵的最大效果。

输入

两个正整数N,M。(1 <= N <= 10^5, N <= M <= 2 * 10^5) 
接下来M行,每一行有三个整数A, B, V。(1 <= A, B <= N, INT_MIN <= V <= INT_MAX) 
保证输入数据合法。

输出

输出一个正整数R,表示符合条件的魔法阵的魔力值之和。

样例输入

4 6
1 2 3
1 3 1
1 4 7
2 3 4
2 4 5
3 4 6

样例输出

12
题解:
1.最大的边尽可能小,那么可以用kurskal算法或者prim算法算法他的最小生成树,记录最大的那条边

2.然后就知道,就算只选取小于这条边的边,也至少能构成1棵树(最小生成树),根据题目要求,优先选择大的边(但要小于1中记录的最大值)

AC代码:

# include <stdio.h>
# include <string.h>
# include <algorithm>
# define inf 0x3f3f3f3f

using namespace std;

int pre[100001];

struct qwe
{
	int x;
	int y;
	long long v;
}a[200002];

void qwe(int n)
{
	int i;
	for (i = 0; i <= n; i ++)
		pre[i] = i;    
}

int Find(int x)  // 找到上一层的结点. 
{
	if (pre[x] != x)
		pre[x] = Find(pre[x]);
		
	return pre[x];
	
}

/*int Find(int x)  // 另外一种 Find 
{
	int p, tmp;
	p = x;
	while (x != pre(x))
		x = pre(x);
	while (p != x)
	{
		tmp = pre[p];
		pre[p] = x;
		p = tmp;
	}
	return x;
}
*/

/*void join(int x, int y)  // 合并树
{
	int p, q;
	p = Find(x);
	q = Find(y);
	
	if (p != q)
		pre[p] = q;
}
*/ 

bool cmp(struct qwe x, struct qwe y)
{
	return x.v < y.v;
}

bool cmp1(struct qwe x, struct qwe y)
{
	return x.v > y.v;
}

int main(void)
{
	int n, m, k;
	long long minn;
	while (~ scanf("%d %d", &n, &m))
	{
		int i;
		qwe(n);  // 初始化数组为他本身 
		for (i = 0; i < m; i ++)
			scanf("%d %d %lld", &a[i].x, &a[i].y, &a[i].v);		
		sort(a, a+m, cmp);  // 先将价值从小到大排序. 
		minn = -inf;
		int sum = 0, c, d;
		for (i = 0; i < m; i ++)
		{
			c = Find(a[i].x);
			d = Find(a[i].y);
			if (c != d)
			{
				sum ++;  // 找出n-1个关系即可 
				minn = max(minn, a[i].v);  // 找出最小值
				pre[c] = d; 
			}
			if (sum == n-1)
				break;
		}
		qwe(n);  // 初始化数组为他本身 
		long long q = 0;
		sum = 0;
		for (i = 0; i < m; i ++)
		{
			if (a[i].v > minn)  // 记录能构成环的值的最小值的位置
			{
				k = i;
				break;
			}
		}
		sort(a, a+k, cmp1);  // 从构成关系的位置价值从大到小排序 
		for (i = 0; i < k; i ++)
		{
			c = Find(a[i].x);
			d = Find(a[i].y);
			if (c != d)
			{
				q += a[i].v;  // 最小值关系的最大值是多少. 
				sum ++;
				pre[c] = d;
			}

			if (sum == n-1)  // 能构成关系 结束. 
				break;
		} 
		printf("%lld\n", q);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liu344439833/article/details/80313839