题意:
如果该图存在次小生成树(与原最小生成树不同,但长度小于等于原最小生成树),则一定可以通过从原最小生成树中去掉一个边并再入一个边得到。
如果要加入一个v1和v2之间的新边,那么则应去掉原有的两点间通路(是唯一通路)中的一条边才能构成生成树。那么为了保证生成树最小,则应去掉原通路上最长的那条边。
对于本题我们的做法是先求最小生成树,然后枚举每一条没有在最小生成树中的边,看加入树中并去掉通路上的最长边后是否与原最小生成数长度相同。
那么如何才能知道要去掉的最长边有多长呢?我们可以在求最小生成树的时候使用Prim算法,我们用一个二维数组f[i][j]记录两点间走树枝路径的最长边。每将一个点加入到最小生成树中的时候,就更新所有已经在最小生成树中的点到该点的路径上的最长边长度。这样建树之后我们便知道了任意两点间的最长边长度。
The Unique MSTTime Limit:1000MS Memory Limit:10000KB 64bit IO Format:%lld & %llu
Description
Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties:
1. V' = V.
2. T is connected and acyclic.
Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'.
Input
Output
Sample Input
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
Sample Output
3 Not Unique!
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
bool vis[MAXN];
int lowc[MAXN];
int pre[MAXN];
int Max[MAXN][MAXN];//Max[i][j]表示在最小生成树中从i到j的路径中的最大边权
bool used[MAXN][MAXN];
int Prim(int cost[][MAXN], int n)
{
int ans = 0;
memset(vis, false, sizeof(vis));
memset(Max, 0, sizeof(Max));
memset(used, false, sizeof(used));
vis[0] = true;
pre[0] = -1;
for (int i = 1; i<n; i++)
{
lowc[i] = cost[0][i];
pre[i] = 0;
}
lowc[0] = 0;
for (int i = 1; i<n; i++)
{
int minc = INF;
int p = -1;
for (int j = 0; j<n; j++)
if (!vis[j] && minc>lowc[j])
{
minc = lowc[j];
p = j;
}
if (minc == INF)return -1;
ans += minc;
vis[p] = true;
used[p][pre[p]] = used[pre[p]][p] = true;
for (int j = 0; j<n; j++)
{
if (vis[j])Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]);
if (!vis[j] && lowc[j]>cost[p][j])
{
lowc[j] = cost[p][j];
pre[j] = p;
}
}
}
return ans;
}
int ans;
int smst(int cost[][MAXN], int n)
{
int Min = INF;
for (int i = 0; i<n; i++)
for (int j = i + 1; j<n; j++)
if (cost[i][j] != INF && !used[i][j])
{
Min = min(Min, ans + cost[i][j] - Max[i][j]);
}
if (Min == INF)return -1;//不存在
return Min;
}
int cost[MAXN][MAXN];
int main()
{
int T;
int n, m;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
int u, v, w;
for (int i = 0; i<n; i++)
for (int j = 0; j<n; j++)
{
if (i == j)cost[i][j] = 0;
else cost[i][j] = INF;
}
while (m--)
{
scanf("%d%d%d", &u, &v, &w);
u--; v--;
cost[u][v] = cost[v][u] = w;
}
ans = Prim(cost, n);
if (ans == -1)
{
printf("Not Unique!\n");
continue;
}
if (ans == smst(cost, n))printf("Not Unique!\n");
else printf("%d\n", ans);
}
return 0;
}