A Za, A Za, Fighting...

坚信:勤能补拙

PKU 1861 Network/PKU 2485 Highways

问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1861
http://acm.pku.edu.cn/JudgeOnline/problem?id=2485

思路:
这里题目并没有明确要求求最小生成树,而是要求一颗最长边最小的生成树
我们可以证明:
       如果T是一颗最小生成树,那么T所包含的最长边一定是所有生成树中最小的,即最小生成树满足题目要求
Prove:
如果T的最长边(x, y)并非最小
那么,存在一颗生成树R,其最长边(u, v)<(x, y),即生成树R的任何一条边都小于(x, y)
现在,采用剪切-粘帖的方法来证明T不是一颗最小生成树,即矛盾
将T中的最长边(x, y)剪切掉,这样就得到两颗子树
在R中,至少存在一条边(p, q)可以将这两颗子树连接起来,这样就得到:
           T - (x, y) + (p, q) < T

代码(这里采用Kruskal算法,并查集实现)
 1 /* union-find sets, Kruskal algorithm */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_N 1001
 6 #define MAX_M 15001
 7 struct Edge{
 8     int len;
 9     int from, to;
10 }edges[MAX_M];
11 int parent[MAX_N], rank[MAX_N];
12 int n, m;
13 
14 void
15 make_set()
16 {
17     int i;
18     for(i=1; i<=n; i++)
19         parent[i] = i;
20     memset(rank, 0sizeof(rank));
21 }
22 
23 int
24 find(int x)
25 {
26     int tmp, rt = x;
27     while(parent[rt] != rt)
28         rt = parent[rt];
29     while(x != rt) {
30         tmp = parent[x];
31         parent[x] = rt;
32         x = tmp;
33     }
34     return rt;
35 }
36 
37 void
38 Union(int x, int y)
39 {
40     int a = find(x);
41     int b = find(y);
42     if(a == b)
43         return;
44     if(rank[a] > rank[b])
45         parent[b] = a;
46     else {
47         parent[a] = b;
48         if(rank[a] == rank[b])
49             ++rank[b];
50     }
51 }
52 
53 int
54 compare(const void *arg1, const void *arg2)
55 {
56     return ((struct Edge *)arg1)->len - ((struct Edge *)arg2)->len;
57 }
58 
59 void
60 init()
61 {
62     int i;
63     for(i=0; i<m; i++
64         scanf("%d %d %d"&edges[i].from, &edges[i].to, &edges[i].len);
65     qsort(edges, m, sizeof(struct Edge), compare);
66 }
67 
68 void
69 kruskal()
70 {
71     int i, a, b, count = 0;
72     int mark[MAX_N];
73     make_set();
74     for(i=0; i<m; i++) {
75         a = find(edges[i].from);
76         b = find(edges[i].to);
77         if(a != b) {
78             mark[count++= i;
79             Union(a, b);
80         }
81     }
82     /* output */
83     printf("%d\n", edges[mark[count-1]].len);
84     printf("%d\n", count);
85     for(i=0; i<count; i++)
86         printf("%d %d\n", edges[mark[i]].from, edges[mark[i]].to);
87 }
88 
89 int
90 main(int argc, char **argv)
91 {
92     while(scanf("%d %d"&n, &m) != EOF) {
93         init();
94         kruskal();
95     }
96 }


posted on 2010-09-05 13:09 simplyzhao 阅读(179) 评论(0)  编辑 收藏 引用 所属分类: F_图算法


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2011年9月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜