poj1679 The Unique MST
这题只是简单的最小生成树的一个变形。 可以用kruskal 先进行求最小生成树, 然后, 用dp 记录每一个点之间的最大长度。 然后枚举每一条边(未在最小生成树中的), 如果发现有和最小生成树中的边的最大相等的就返回不唯一, 否则如果都大的话, 返回唯一
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #include<algorithm> #define maxn 102 using namespace std; struct node { int left, right, val; }map[maxn* maxn], edge[maxn * maxn]; int e[maxn][maxn]; int map_count; int parent[maxn]; int n, m, sum; int edge_min[maxn][maxn]; int fleft, fright, fval; void add(int left, int right) { edge_min[left][0] ++; edge_min[left][edge_min[left][0]] = right; edge_min[right][0] ++; edge_min[right][edge_min[right][0]] = left; } void del(int left, int right) { int k = 1; while (edge_min[left][k] != right)k ++; while (k < edge_min[left][0]) edge_min[left][k] = edge_min[left][k + 1], k ++; k = 1; while (edge_min[right][k] != left) k ++; while (k < edge_min[right][0]) edge_min[right][k] = edge_min[right][k + 1], k ++; edge_min[left][0]--; edge_min[right][0] --; } int find(int x) { if (x != parent[x]) x = find(parent[x]); return parent[x]; } int point_find; void find_max(int parent, int current, int left , int right, int val) { if (point_find == current) { fleft = left; fright = right; fval = val; return; } for (int i = 1; i <= edge_min[current][0]; i ++) { if (parent != edge_min[current][i]) { if (e[current][edge_min[current][i]] > val) { find_max(current, edge_min[current][i], current, edge_min[current][i], e[current][edge_min[current][i]]); } else { find_max(current, edge_min[current][i], left, right, val); } } } return; } int cmp(const node &a , const node &b) { if (a.val <= b.val) { return true; } return false; } void init() { int i, x, y, val; for (i = 1; i <= n; i ++) { parent[i] = i; } for (i = 0; i < m; i ++) { scanf("%d%d%d", &edge[i].left, &edge[i].right, &edge[i].val); e[edge[i].left][edge[i].right] = e[edge[i].right][edge[i].left] = edge[i].val; } map_count = 0; sort(edge, edge + m, cmp); memset(edge_min, 0, sizeof(edge_min)); } void krus() { int i = 0, cou = 0; sum = 0; int left, right, left_parent, right_parent, val; for (i = 0; i < m; i ++) { left = edge[i].left; right = edge[i].right; left_parent = find(left); right_parent = find(right); if (left_parent != right_parent) { parent[left_parent] = parent[right_parent]; add(left, right); sum += edge[i].val; cou++; } else { find_max(left, right, 0, 0, 0); if (fval > edge[i].val) { sum = sum + edge[i].val - fval; del(fleft, fright); map_count ++; map[map_count].left = fleft; map[map_count].right = fright; map[map_count].val = fval; add(edge[i].left, edge[i].right); } else { map_count ++; map[map_count] = edge[i]; } } if (cou == n - 1) { break; } } i ++; while ( i < m) { map_count ++; map[map_count] = edge[i ++]; } return; } int max_left[maxn][maxn], max_right[maxn][maxn]; int max_val[maxn][maxn]; void dfs(int parent, int current, int left, int right, int val) { int x; for (int i = 1; i <= edge_min[current][0]; i ++) { x = edge_min[current][i]; if (x != parent) { if (e[current][x] > val) { max_left[point_find][x] = current; max_right[point_find][x] = x; max_val[point_find][x] = e[current][x]; dfs(current, x, current, x, e[current][x]); } else { max_left[point_find][x] =left; max_right[point_find][x] = right; max_val[point_find][x] = val; dfs(current, x, left, right, val); } } } } bool judge() { for (int i = 1; i <= n ; i ++) { point_find = i; dfs(i, i, 0, 0, 0); } for (int i = 1; i <= map_count; i ++) { if (max_val[map[i].left][map[i].right] == map[i].val) { return false; } } return true; } int main() { int count_int; scanf("%d", &count_int); while (count_int --) { scanf("%d%d", &n, &m); init(); krus(); if (judge()) { printf("%d\n", sum); } else { printf("Not Unique!\n"); } } return 0; }