题意:
给你一个图,问你最小生成树是否唯一?
思路:
其实就是求次小生成树,如果最小生成树和次小生成树的花费一样那么,最小生成树就不是唯一的。
这题用了一些技巧,稍稍修改了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;
}