您的位置:首页 > 产品设计 > UI/UE

POJ 1679 The Unique MST

2013-12-04 23:55 405 查看
题意:给一个图,判断它的最小生成树唯一不唯一。

解法:首先,容易想到一个O(n^3)或者说O(m*n^2)的方法。就是首先,求一遍最小生成树,记权值和为x1,然后枚举最小生成树中的每一条边,在不用该边的情况下求出的最小生成树权值和为x2,若枚举到某条边的时候x1 = x2,则最小生成树不唯一。若全不相等,则唯一。

   但是,觉得这个方法太慢了,上网搜索了一下搜到了这篇文章,https://www.byvoid.com/blog/2-sp-mst,求次小生成树。(这道题相当于判定最小生成树和次小生成树权值和是否相等)

   上面那篇文章的方法,中心思想在于:枚举每条不在最小生成树中的边,若将它加入最小生成树,一定会生成环,去掉环中的最长边,则是新的最小生成树,若去掉的边权值和加入的边权值相同,则最小生成树和次小生成树权值和相同。当然,这样写的话,时间复杂度也可能打到O(n^3),但是,基于这个思想,能有O(n^2 + m)的写法。

   O(n^2+m)的写法为,从每个节点i遍历整个最小生成树,定义f[j]为最小生成树上从i到j的边中权值最大边的权值,然后遍历所有不在最小生成树中的边(i, k)比较w(i, k)和f[k]的大小,若相等则最小生成树不唯一。

tag:MST,次小生成树

解法一O(n^3):

/*
* Author:  Plumrain
* Created Time:  2013-12-04 19:35
* File Name: G-POJ-1679-2.cpp
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

#define CLR(x) memset(x, 0, sizeof(x))
#define CLR1(x) memset(x, -1, sizeof(x))
#define PB push_back

struct Pat{
int s, e, w;
};

int n, m;
Pat p[10005];
bool vis[105][105];
int d[105][105], f[105];
int cnt[105];
vector<int> nod[105];

bool cmp(Pat a, Pat b)
{
return a.w < b.w;
}

void init()
{
CLR (vis);
CLR1 (d);

scanf ("%d%d", &n, &m);
for (int i = 0; i < m; ++ i){
scanf ("%d%d%d", &p[i].s, &p[i].e, &p[i].w);
-- p[i].s; -- p[i].e;
d[p[i].s][p[i].e] = p[i].w;
d[p[i].e][p[i].s] = p[i].w;
}
sort (p, p+m, cmp);

for (int i = 0; i < n; ++ i)
nod[i].clear();
}

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

int kruskal()
{
for (int i = 0; i < n; ++ i)
f[i] = i;

int cost = 0;
for (int i = 0; i < m; ++ i){
int s = p[i].s, e = p[i].e, w = p[i].w;
int t1 = find(s), t2 = find(e);
if (t1 != t2){
f[t1] = t2;
cost += w;
nod[s].PB (e);
nod[e].PB (s);
vis[e][s] = vis[s][e] = 1;
}
}

int tmp;
for (int i = 0; i < n; ++ i){
if (!i) tmp = find(i);
else if (tmp != find(i)) return -1;
}
return cost;
}

void dfs(int x, int ma)
{
if (cnt[x] != -1) return;

cnt[x] = ma;
int sz = nod[x].size();
for (int i = 0; i < sz; ++ i)
if (cnt[nod[x][i]] == -1)
dfs (nod[x][i], max(d[x][nod[x][i]], ma));
}

int main()
{
int T;
scanf ("%d", &T);
while (T--){
init();
int ans = kruskal();
if (ans == -1){
printf ("0\n");
continue;
}
bool ok = 0;
for (int i = 0; i < n; ++ i){
CLR1 (cnt);
dfs (i, 0);

for (int j = 0; j < n; ++ j) if (i != j && !vis[i][j])
if (cnt[j] == d[i][j]) ok = 1;
}
if (!ok) printf ("%d\n", ans);
else printf ("Not Unique!\n");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: