先用kruskal算法算出最小生成树,并把最小生成树的边记录下来。然后依次枚举删除边,用其他的边再次使用kruskal算法算出最小生成树。如果算出的代价和原来的相同,则不唯一,否则唯一。另外当我们删除一条边之后,可能根本构不成一颗生成树,要判断一下。
代码如下:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <new>
#include <set>
#include <map>
using namespace std;
const int maxn = 1000;
int p[maxn], x[maxn], y[maxn], n;
struct edge
{
int u, v, cost;
bool operator < (const edge& b) const
{
return cost < b.cost;
}
};
vector<edge> edges;
vector<int> mst_edges;
int find_root(int x)
{
if (p[x] == -1) return x;
return p[x] = find_root(p[x]);
}
void kruskal()
{
memset(p, -1, sizeof(p));
sort(edges.begin(), edges.end());
mst_edges.clear();
int cost = 0;
for (int i = 0; i < edges.size(); i++)
{
int x = edges[i].u, y = edges[i].v;
int rx = find_root(x);
int ry = find_root(y);
if (rx != ry)
{
p[rx] = ry;
cost += edges[i].cost;
mst_edges.push_back(i);
}
}
printf("%d\n", cost);
bool ok = false;
for (int i = 0; i < mst_edges.size(); i++)
{
memset(p, -1, sizeof(p));
int ans = 0, k = 0;
for (int j = 0; j < edges.size(); j++)
{
if (mst_edges[i] == j) continue;
int x = edges[j].u, y = edges[j].v;
int rx = find_root(x);
int ry = find_root(y);
if (rx != ry)
{
p[rx] = ry;
ans += edges[j].cost;
k++;
}
}
if (ans == cost && k == n - 1)//新算出的生成树的代价和最小生成树代价相同,且能构成一棵树(最小生成树的边数肯定是n - 1)
{
ok = true;
break;
}
}
if (ok) printf("Yes\n");
else printf("No\n");
}
int main()
{
//freopen("1.txt", "r", stdin);
int T, Case = 0;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
edges.clear();
for (int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]);
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
{
int d = abs(x[i] - x[j]) + abs(y[i] - y[j]);
edges.push_back(edge{i, j, d});
}
printf("case #%d:\n", Case++);
kruskal();
}
return 0;
}