POJ2395 Out of Hay - Kruskal算法

Out of Hay

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 20765   Accepted: 8208

Description

The cows have run out of hay, a horrible event that must be remedied immediately. Bessie intends to visit the other farms to survey their hay situation. There are N (2 <= N <= 2,000) farms (numbered 1…N); Bessie starts at Farm 1. She’ll traverse some or all of the M (1 <= M <= 10,000) two-way roads whose length does not exceed 1,000,000,000 that connect the farms. Some farms may be multiply connected with different length roads. All farms are connected one way or another to Farm 1.

Bessie is trying to decide how large a waterskin she will need. She knows that she needs one ounce of water for each unit of length of a road. Since she can get more water at each farm, she’s only concerned about the length of the longest road. Of course, she plans her route between farms such that she minimizes the amount of water she must carry.

Help Bessie know the largest amount of water she will ever have to carry: what is the length of longest road she’ll have to travel between any two farms, presuming she chooses routes that minimize that number? This means, of course, that she might backtrack over a road in order to minimize the length of the longest road she’ll have to traverse.
Input

  • Line 1: Two space-separated integers, N and M.

  • Lines 2…1+M: Line i+1 contains three space-separated integers, A_i, B_i, and L_i, describing a road from A_i to B_i of length L_i.
    Output

  • Line 1: A single integer that is the length of the longest road required to be traversed.

Sample Input

3 3
1 2 23
2 3 1000
1 3 43

Sample Output

43
Hint

OUTPUT DETAILS:

In order to reach farm 2, Bessie travels along a road of length 23. To reach farm 3, Bessie travels along a road of length 43. With capacity 43, she can travel along these roads provided that she refills her tank to maximum capacity before she starts down a road.

 
 

题目大概意思:

给出一个含 N ( 2 N 2 × 1 0 3 ) N(2≤N≤2×10^3) 个节点, M ( 1 M 1 0 4 ) M(1≤M≤10^4) 个边的连通图,第 i i 条边连接节点 A A B B ,边权为 C i ( C i 1 0 9 ) C_i(C_i≤10^9) 。求一生成树,使得生成树中边权最大的边的边权最小,输出这个最小的最大值。

 
 

分析:

最小化最大值问题,首先想到二分求解,即每次选定一个最大值,只使用边权小于等于该最大值的边,判断能否构成生成树,算法时间复杂度为 O ( M log 2 C m a x ) O(M·\log_2{C_{max}}) 。但此题我门还可以使用更为高效的无需二分求解办法,即:

  1. 先按照边权从小到大将边排序。
  2. 从左到右遍历每条边,利用 K r u s k a l Kruskal 算法 的思想:如果当前边的两个端点尚未在一个集合,则合并这两个节点所在的集合,并更新答案。

由于是按边权从小到大遍历每条边,因此最终得到的必是最优解。且由于题目保证了图的连通性,执行结束后无需判断形成的是否是森林。算法的时间复杂度为 O ( M α ( N ) ) O(M·\alpha(N)) ,明显优于二分求解。

 
 
下面贴代码:

#include <cstdio>
#include <algorithm>
using namespace std;


const int MAX_N = 2005;
const int MAX_M = 10005;

struct P
{
	int par;
	int rank;
};

struct Edge
{
	int u;
	int v;
	int cost;
	bool operator< (const Edge& _Right)const
	{
		return cost < _Right.cost;
	}
};

void init(const int N);
int findpar(int x);
bool unite(int x, int y);
bool same(int x, int y);

P v[MAX_N];
Edge E[MAX_M];

int main()
{
	int N, M;

	scanf("%d%d", &N, &M);
	init(N);

	for (int i = 0; i < M; ++i)
	{
		Edge& e = E[i];
		scanf("%d%d%d", &e.u, &e.v, &e.cost);
	}
	sort(E, E + M);

	int ans = 0;
	for (int i = 0; i < M; ++i)
	{
		const Edge& e = E[i];
		if (unite(e.u, e.v))
		{
			ans = e.cost;
		}
	}
	printf("%d\n", ans);

	return 0;
}

void init(const int N)
{
	for (int i = 0; i <= N; ++i)
	{
		v[i].par = i;
		v[i].rank = 0;
	}
}

int findpar(int x)
{
	if (v[x].par == x)
	{
		return x;
	}
	return v[x].par = findpar(v[x].par);
}

bool unite(int x, int y)// 如果合并成功, 返回 true, 否则返回 false
{
	x = findpar(x);
	y = findpar(y);
	if (x != y)
	{
		if (v[x].rank < v[y].rank)
		{
			v[x].par = y;
		}
		else if (v[x].rank == v[y].rank)
		{
			v[x].par = y;
			++v[y].rank;
		}
		else
		{
			v[y].par = x;
		}
		return true;
	}
	return false;
}

bool same(int x, int y)
{
	return findpar(x) == findpar(y);
}

原创文章 42 获赞 22 访问量 3050

猜你喜欢

转载自blog.csdn.net/weixin_44327262/article/details/97752392