| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 20421 | Accepted: 7183 |
Description
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!
Source
这题做得好开心,一次AC~
题意:给定一个联通图,判断最小生成树是否唯一。
题解:求出最小生成树后再求次小生成树,若次小生成树的长度与最小生成树相等就说明不唯一,否则唯一。
这是我的第一道次小生成树题,在这里总结下这个算法:
利用一个矩阵max【】【】表示最小生成树中任意两点路径上的最长边权值(关键!!),在求最小生成树时将已经选上的边标记为已用,求完后,遍历剩下未用的边,这条边若添加到最小树中必定构成回路,所以此时需要去掉原来树中那条回路中的最大值,也就是max矩阵存储的值,所以问题转换成找到一条未用的边,使得它跟对应于max矩阵里的边差值最小,遍历之后,次小生成树的值即为原最小生成树的值加上这个最小的差值。
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define maxn 102
#define maxm (maxn * maxn) >> 1
int head[maxn], max[maxn][maxn];
struct Node{
int u, v, cost, next;
bool vis;
} E[maxm];
bool vis[maxn];
int mini(int a, int b){
return a < b ? a : b;
}
int prim(int n, int m)
{
int u, i, tmp, j, len = 0, count = 0;
memset(max, 0x7f, sizeof(max));
memset(vis, 0, sizeof(vis));
vis[1] = 1;
while(count < n - 1){
for(i = 1, tmp = INT_MAX; i <= n; ++i){
if(!vis[i]) continue;
for(j = head[i]; j != -1; j = E[j].next){
if(vis[E[j].v]) continue;
if(E[j].cost < tmp){
tmp = E[j].cost; u = j;
}
}
}
++count; len += tmp;
for(i = 1; i <= n; ++i){
if(!vis[i]) continue;
max[i][E[u].v] = max[E[u].v][i] = E[u].cost;
}
vis[E[u].v] = 1; E[u].vis = 1;
}
return len;
}
int getSecLen(int n, int m)
{
int min = INT_MAX, u, v, w;
for(int i = 0; i < m; ++i){
if(E[i].vis) continue;
u = E[i].u; v = E[i].v;
w = E[i].cost;
min = mini(min, w - max[u][v]);
if(min == 0) return 0;
}
return min;
}
int main()
{
int t, n, m, i, minLen, secLen;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
memset(head, -1, sizeof(head));
for(i = 0; i < m; ++i){
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].cost);
E[i].vis = 0; E[i].next = head[E[i].u];
head[E[i].u] = i;
}
minLen = prim(n, m);
secLen = getSecLen(n, m);
if(secLen == 0) printf("Not Unique!\n");
else printf("%d\n", minLen);
}
return 0;
}POJ1679 The Unique MST 【次小生成树】,布布扣,bubuko.com
POJ1679 The Unique MST 【次小生成树】
原文:http://blog.csdn.net/chang_mu/article/details/38490315