紫书 例题 11-2 UVa 1395(最大边减最小边最小的生成树)

思路:枚举所有可能的情况。

枚举最小边, 然后不断加边, 直到联通后, 这个时候有一个生成树。这个时候,在目前这个最小边的情况可以不往后枚举了,

可以直接更新答案后break。

 因为题目求最大边减最小边最小, 在最小边确定的情况下, 要使得差值最小, 就要使得最大边最小, 那么排序之后加边后

的第一个生成树一定是此情况下的最优解, 因为这个时候最大边最小, 后面的边肯定更大。

细节(1)注意题目给的点标号从1开始还是从0开始。(2)边数组可以用vector(3)find函数最后 return f[x]。


#include<cstdio>
#include<vector>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

const int MAXN = 112;
struct node
{
	int w, u, v;
	node(int u = 0, int v = 0, int w = 0) : u(u), v(v), w(w) {}
	bool operator < (const node& rhs) const
	{
		return w < rhs.w;
	}
};
vector<node> Edge;
int f[MAXN], n, m;

int find(int x)
{
	if(f[x] != x)
		f[x] = find(f[x]);
	return f[x];
}

int main()
{
	while(~scanf("%d%d", &n, &m) && n)
	{
		Edge.clear();
		REP(i, 0, m)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			Edge.push_back(node(u, v, w));
		}
		
		sort(Edge.begin(), Edge.end());

		int ans = 1e9;
		REP(L, 0, m)
		{
			int sum = 0;
			REP(i, 1, n + 1) f[i] = i;
			REP(R, L, m)
			{
				int u = find(Edge[R].u), v = find(Edge[R].v);
				if(u != v) 
				{
					f[u] = v;
					if(++sum == n - 1)
					{
						ans = min(ans, Edge[R].w - Edge[L].w);
						break;
					}
				}
			}
		}
		
		printf("%d\n", ans == 1e9 ? -1 : ans);
	}

	return 0;
}

posted @ 2018-05-21 18:48  Sugewud  阅读(98)  评论(0编辑  收藏  举报