poj-2054 Color a Tree ****

  1 /*
2 * POJ-2054 color a tree
3 *
4 * 贪心 难题!
5 *
6 * 思路1:
7 * http://hi.baidu.com/cheezer94/blog/item/d98eca065202a2f237d122da.html
8 * 思路2:
9 * http://www.cnblogs.com/X-Kly/archive/2011/11/02/POJ2054.html
10 * 代码:
11 * http://xinbaolianmeng.com/showshouye.aspx?type=7&ID=110
12 *
13 * 简单讲:
14 * 每次找到 权值最大的“集合”, 与其“父集合”合并, 权值为 两个集合中 顶点权值的平均。
15 * 直到只剩一个集合
16 *
17 *
18 * 下面有范例代码, 一样, 可看其注释
19 *
20 *
21 */
22
23
24 #include <cstdio>
25 using namespace std;
26
27 const int maxn = 1000 + 5;
28
29 int n, r;
30 int c[maxn], fa[maxn];
31 int pre[maxn], next[maxn], sum[maxn], num[maxn];
32 bool vis[maxn];
33
34 int find_max(){
35 double max = -1;
36 int maxNum = -1;
37 for(int i=1; i<=n; i++){
38 if(!vis[i] && (sum[i] * 1.0 / num[i]) > max){
39 max = (sum[i] * 1.0 / num[i]);
40 maxNum = i;
41 }
42 }
43 return maxNum;
44 }
45
46
47 void unionFa(int x){
48 int faSet;
49 for(faSet=fa[x]; pre[faSet]!=-1; faSet = pre[faSet]);
50 sum[faSet] += sum[x];
51 num[faSet] += num[x];
52 for(faSet=fa[x]; next[faSet]!=-1; faSet = next[faSet]);
53 next[faSet] = x;
54 pre[x] = faSet;
55
56 vis[x] = 1;
57 }
58
59 int main(){
60 while(scanf("%d%d", &n, &r)){
61 if(n == 0) return 0;
62
63 for(int i=1; i<=n; i++){ //注意从1开始!!(因为输入的根、边的标号都是从1开始的)
64 scanf("%d", &c[i]);
65 sum[i] = c[i];
66 num[i] = 1;
67 pre[i] = next[i] = -1;
68 vis[i] = false;
69 }
70
71 int u, v;
72 for(int i=1; i<n; i++){
73 scanf("%d%d", &u, &v);
74 fa[v] = u;
75 }
76
77 int d;
78 vis[r] = 1;
79 while(1){
80 d = find_max();
81 if(d == -1) break;
82 unionFa(d);
83 }
84
85 int ans = 0, t = 1;
86 for(int i=r; i!=-1; i=next[i]){
87 ans += t * c[i];
88 t++;
89 }
90 printf("%d\n", ans);
91 }
92
93
94 return 0;
95 }
96
97 /* ===================== 范例程序 有注释 ================================
98
99 #include<iostream>
100   #include <cstdio>
101 using namespace std;
102 const int max_n=1010;
103 int pre[max_n];//pre[i]用来表示当前集合(包含i)的上个元素
104 int next[max_n];//next[i]用来表示当前集合(包含i)的下个元素
105 int c[max_n];
106 int num[max_n];//num[i]表示当前集合(包含i)的元素个数
107 int visit[max_n];
108 int sum[max_n];//当前集合元素和
109 int father[max_n];//father[i]表示i的父元素
110 int n,r;
111 int find_max()//找到当前权值最大的集合,合并后的点当做一个集合,也就是一个点
112 {
113 double max=0;
114 int bh=-1;
115 for(int i=1;i<=n;i++)
116 {
117 if(max<(sum[i]*1.0)/num[i]&&visit[i]==0)
118 {
119 max=(sum[i]*1.0)/num[i];
120 bh=i;
121 }
122 }
123 return bh;
124 }
125 void uni(int x)//联合
126 {
127 int i;
128 for(i = father[x]; pre[i] != -1; i = pre[i]);//找到父元素所在的集合
129 sum[i]+=sum[x];
130 num[i]+=num[x];
131 for(i = father[x]; next[i] != -1; i = next[i]);//找到父元素所在集合的底元素
132 next[i]=x;
133 pre[x]=i;
134 visit[x]=1;
135 }
136 int main()
137 {
138
139 while(scanf("%d %d",&n,&r),n&&r)
140 {
141 for(int i=1;i<=n;i++)
142 {
143 scanf("%d",&c[i]);
144 sum[i]=c[i];
145 visit[i] =0;
146 pre[i] = next[i] = -1;
147 num[i] = 1;
148 }
149 for(int i = 1; i < n; i++)
150 {
151 int a, b;
152 scanf("%d %d", &a, &b);
153 father[b] = a;
154 }
155
156 int d;
157 visit[r]=1;
158 while(1)
159 {
160 d=find_max();
161 if(d==-1)break;
162 uni(d);
163 }
164 int ans=0,tjq=1;
165 for(int i=r;i!=-1;i=next[i])
166 {
167 ans+=tjq*c[i];
168 tjq++;
169 }
170 printf("%d\n",ans);
171 }
172
173 return 0;
174 }
175
176 */

posted on 2012-03-11 19:43  龙豆  阅读(815)  评论(0编辑  收藏  举报

导航