POJ 1679 最小生成树是否唯一 次小生成树

题意:

给你一个图,问你最小生成树是否唯一?

思路:

其实就是求次小生成树,如果最小生成树和次小生成树的花费一样那么,最小生成树就不是唯一的。

这题用了一些技巧,稍稍修改了kruscal算法,对于每条边,如果有一条和它花费相同的边存在,那么就删去它同时求最小生成树,并进行判断

<pre name="code" class="cpp">#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#define MAX_E 5000
using namespace std;
bool first;
int par[MAX_E];
int ranks[MAX_E];
struct edge
{
	int u, v;
	int cost;
	bool equ;//记录是否存在和这条边花费相等的边
	bool del;//这条边是否被删除
	bool used;//这条边是否在最小生成树中被使用

};

edge es[MAX_E];
int V, E;

void init(int n)
{
	for (int i = 1; i <= n; i++)//注意初始化范围
	{
		par[i] = i;
		ranks[i] = 0;
	}
}
int find(int x)
{
	if (par[x] == x)
	{
		return x;
	}
	else
	{
		return par[x] = find(par[x]);
	}
}
void unite(int x, int y)
{
	x = find(x);
	y = find(y);
	if (x == y)  return;
	if (ranks[x] < ranks[y])
	{
		par[x] = y;
	}
	else
	{
		par[y] = x;
		if (ranks[x] == ranks[y]) ranks[x] ++;
	}
}
bool same(int x, int y)
{
	return find(x) == find(y);
}
bool comp(const edge &e1, const edge &e2)
{
	return e1.cost < e2.cost;
}
int kruskal()
{
	sort(es, es + E, comp);
	init(V);
	int res = 0;
	for (int i = 0; i < E; i++)
	{
		edge e = es[i];
		if ((!same(e.v, e.u)) && (!e.del))//注意判断这条边是否被删除
		{
			unite(e.u, e.v);
			if(first)es[i].used = 1;//在第一次求最小生成树的时候记录这条边被使用了
			res += e.cost;
		}
	}
	return res;
}



int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		cin >> V >> E;
		for (int i = 0; i < E; i++)
		{
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			es[i].u = u;
			es[i].v = v;
			es[i].cost = w;
			es[i].del = 0;
			es[i].equ = 0;
			es[i].used = 0;
		}
		first = true;//表示是否是第一次求最小生成树
		int res1 = kruskal();
		first = false;
		int i;
		for (int i = 0; i < E; i++) {
			for (int j = 0; j < E; j++) {
				if (i == j)continue;
				if (es[i].cost == es[j].cost) {
					es[i].equ = 1;
				}
			}
		}
			


		for (i = 0; i < E; ++i)
		{
			if (es[i].used && es[i].equ)
			{
				es[i].del = 1;//如果存在花费相等的边就删去这条边并求最小生成树
				int res2 = kruskal();
				if (res1 == res2)
				{
					printf("Not Unique!\n");
					break;
				}
				es[i].del = 0;
			}


		}
		if (i >= E) printf("%d\n", res1);
		
	}
	return 0;
}




                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值