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; }