题目链接:http://poj.org/problem?id=1679
题目大意:
判断一个连通的无向图的最小生成树是不是唯一的,如果唯一,输出最小生成树的权值,否者输出“Not Unique!”
题目思路:
这题目看的书上的,其实,最开始我的想法是,在求最小生成树的过程中,如果扩展到某一个点的时候,有多种选择,也就是说,有多个权值相同的边可以选择,那么就break掉,说明最小生成树不唯一。其实这是有问题的,因为,很可能在这权值相同的边当中,只能选择其中一条,如果选择其它的就得不到最小生成树,这就是一个反例。所以原来的做法是错误的。
书上的做法是,首先,预处理,看每个边是不是有别的边的权值和它一样的,有的话就标记一下,用结构体里面的equal表示,然后用kruscal算法求一遍最小生成树,并且把这棵最小生成树里面的边都标记一下,用结构体里面的used表示,然后,对于那种有其他边和它权值相同的那种边,同时这条边在第一次求的最小生成树里面,我们就把它删除,做法就是用结构体里面的del标记,然后再次求一遍最小生成树,不用del被标记的边,这样如果求出来的最小生成树的权值和原来的一样,说明最小生成树不唯一,break;
然后就OK了,唉,其实这是很自然的一个想法~
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cctype> 6 #include <stack> 7 #include <queue> 8 #include <map> 9 #include <set> 10 #include <vector> 11 #include <cmath> 12 #include <algorithm> 13 #define lson l, m, rt<<1 14 #define rson m+1, r, rt<<1|1 15 using namespace std; 16 typedef long long int LL; 17 const int MAXN = 0x3f3f3f3f; 18 const int MIN = -0x3f3f3f3f; 19 const double eps = 1e-9; 20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1}, 21 {1,1},{1,-1},{-1,-1}}; 22 const int MAX = 100+10; 23 typedef struct Edge { 24 int u, v, w, equal, used, del; 25 bool operator < (const Edge &other) const { 26 return w < other.w; 27 //别把排序搞反了!!呵呵 28 } 29 }Edge; 30 Edge edge[6000]; 31 int parent[MAX], n,m; 32 bool first; 33 void init() { 34 for (int i = 1; i <= n; ++i) parent[i]= -1; 35 } 36 int Find(int x) { 37 int s; 38 for (s = x; parent[s] >= 0; s = parent[s]) ; 39 while ( s != x) { 40 int tmp = parent[x]; parent[x]= s; x = tmp; 41 } 42 return s; 43 } 44 void Union(int R1, int R2) { 45 int r1 = Find(R1), r2 = Find(R2), tmp = parent[r1] + parent[r2]; 46 if (parent[r1] > parent[r2]) { 47 parent[r1] = r2; parent[r2] = tmp; 48 } else { 49 parent[r2] = r1; parent[r1] = tmp; 50 } 51 } 52 int kruscal() { 53 int sum = 0, num = 0; 54 int u, v, i, j; 55 init(); 56 for (i = 1; i<=m; ++i) { 57 if (edge[i].del == 1) continue; 58 u = edge[i].u; v = edge[i].v; 59 if (Find(u) != Find(v)) { 60 sum += edge[i].w; Union(u, v); num++; 61 if (first == true) edge[i].used = 1; 62 } 63 if (num >= n - 1) break; 64 } 65 return sum; 66 } 67 int main(void){ 68 #ifndef ONLINE_JUDGE 69 freopen("poj1679.in", "r", stdin); 70 #endif 71 int u, v, w, i, j, k, t; 72 scanf("%d", &t); 73 while (t--) { 74 scanf("%d%d", &n, &m); 75 edge[0].w=0; 76 for (j = 1; j <= m; ++j) { 77 scanf("%d%d%d", &u, &v, &w); 78 edge[j].u = u; edge[j].v = v; edge[j].w = w; 79 edge[j].equal = edge[j].del = edge[j].used = 0; 80 } 81 for (j = 1; j <= m; ++j) { 82 for (k = j+1; k <= m; ++k) { 83 if (edge[k].w == edge[j].w) edge[j].equal=edge[k].equal= 1; 84 } 85 } 86 sort(edge + 1, edge + m + 1); 87 first = true; 88 int weight1 = kruscal(), weight2; 89 first = false; 90 for (j = 1; j <= m; ++j) { 91 if (edge[j].used && edge[j].equal) { 92 edge[j].del = 1; weight2 = kruscal(); 93 if (weight2 == weight1) { 94 printf("Not Unique!\n"); break; 95 } 96 edge[j].del = 0; 97 } 98 } 99 if (j > m) printf("%d\n", weight1); 100 } 101 102 return 0; 103 }
写的过程中,出现了一个错误,导致开始运行怎么也不对,就是结构体里面的运算符重载小于号写反了……因为要从小到大排序,所以都写成小于号。