poj 1639 有限制的最小生成树

解题思路比较明确,但代码量之大细节之多,就没写,把一位大牛的代码先放这,学的思路清晰。(有时间这道题一定要再写一遍)。

View Code
  1 #include <iostream> 
2 #include <algorithm>
3 #include <string>
4 #define MAX_N 25
5 using namespace std;
6
7 //记录所有节点名
8 struct node
9 {
10 string name;
11 int con[MAX_N + 1]; //记录原始的当前点与其他点间边的权值
12 }nodes[MAX_N + 1];
13 int nodesn; //结点数量
14 int kdeg; //最小限度数
15 struct edge //用来记录所有边
16 {
17 int from, to, w;
18 edge()
19 {
20 from = to = w = 0;
21 }
22 }edges[MAX_N * MAX_N + 1];
23 int edgen;
24 int graph[MAX_N + 1][MAX_N + 1];
25 int color[MAX_N + 1]; //用于标记联通分量
26 int bfsq[MAX_N + 1][4], head, tail;
27 bool v[MAX_N + 1];
28 void init()
29 {
30 memset(nodes, 0, sizeof(nodes));
31 memset(graph, 0, sizeof(graph));
32 nodesn = 0;
33 edgen = 0;
34 }
35 int getIndex(const string &str)
36 {
37 for(int i = 0; i < nodesn; i++)
38 if(nodes[i].name == str)
39 return i;
40 return -1;
41 }
42 //插入边[str1, str2, w]
43 void processNodes(const string &str1, const string &str2, int w) //nodes记录结点信息
44 {
45 int index1 = getIndex(str1); // 查找
46 if(index1 == -1)
47 {
48 index1 = nodesn++;
49 nodes[index1].name = str1;
50 }
51 int index2 = getIndex(str2);
52 if(index2 == -1)
53 {
54 index2 = nodesn++;
55 nodes[index2].name = str2;
56 }
57 nodes[index1].con[index2] = w;
58 nodes[index2].con[index1] = w;
59 if(str1 != "Park" && str2 != "Park") //edges记录给定点除外的信息
60 {
61 edges[edgen].from = index1;
62 edges[edgen].to = index2;
63 edges[edgen].w = w;
64 edgen++;
65 }
66 }
67 int cmp(const edge &e1, const edge &e2) //有小到大排序
68 {
69 return e1.w <= e2.w;
70 }
71
72 //并查集相关
73 int sets[MAX_N + 1];
74 int find(int id)
75 {
76 while (id!=sets[id])
77 id=sets[id];
78 return id;
79 }
80
81 void joint(int id1, int id2)
82 {
83 int sid1 = find(id1), sid2 = find(id2);
84 if(sid1 == sid2) return;
85 else sets[sid1] = sid2;
86 }
87
88 //Kruskal 算法, //返回联通分量的个数
89 int solveMST(int root)
90 {
91 int e = 0, t, colorseq = 0;
92 for(e = 0; e < nodesn; e++)
93 {
94 color[e] = 0;
95 sets[e] = e;
96 }
97 for(e = 0; e < edgen; e++)
98 {
99 int from = edges[e].from;
100 int to = edges[e].to;
101 int w = edges[e].w;
102 if(find(from) == find(to)) continue;
103 else
104 {
105 joint(from, to);
106 graph[from][to] = graph[to][from] = w;
107 }
108 }
109
110 //着色
111 for(e = 0; e < nodesn; e++) //统计连通分量个数
112 {
113 if(color[e] || e == root) continue;
114 int sid = find(e);
115 color[e] = ++colorseq;
116 for(t = e + 1; t < nodesn; t++)
117 {
118 if(t == root) continue;
119 if(!color[t] && find(t) == sid)
120 color[t] = color[e];
121 }
122 }
123 return colorseq;
124 }
125
126 //统计记录从root 到 当前tree中所有点路径上除去和root直连的边中的权值最大的边的 from to weight
127 void getMaxEdgeInPath(int root, int maxarray[][3])
128 {
129 head = tail = 1;
130 memset(bfsq, 0, sizeof(bfsq));
131 memset(v, 0, sizeof(v));
132 bfsq[tail][0] = root;
133 bfsq[tail][3] = 0;
134 tail = tail % MAX_N + 1;
135 v[root] = true;
136 while(head != tail)
137 {
138 int curId = bfsq[head][0];
139 int from = bfsq[head][1];
140 int to = bfsq[head][2];
141 int curMax = bfsq[head][3];
142 head = head % MAX_N + 1;
143 if(curId != root && from != root)
144 {
145 maxarray[curId][0] = from;
146 maxarray[curId][1] = to;
147 maxarray[curId][2] = curMax;
148 }
149 for(int toid = 0; toid < nodesn; toid++)
150 {
151 int curW;
152 if(v[toid] || (curW = graph[curId][toid]) == 0) continue;
153 v[toid] = true;
154 int fromm = from, too = to, curMaxx = curMax;
155 if(curW > curMax && curId != root)
156 {
157 fromm = curId;
158 too = toid;
159 curMaxx = curW;
160 }
161 bfsq[tail][0] = toid;
162 bfsq[tail][1] = fromm;
163 bfsq[tail][2] = too;
164 bfsq[tail][3] = curMaxx;
165 tail = tail % MAX_N + 1;
166 }
167 }
168 }
169
170 void solveKDegreeContraintTree()
171 {
172 //记录从root 到 当前tree中所有点路径上除去和root直连的边中的权值最大的边的 from to weight
173 int maxEdgeInPath[MAX_N + 1][3];
174 //记录点是否和root直连
175 bool conDirectToRoot[MAX_N + 1];
176 //记录root和每一个连通分量之间权值最小的边及权值
177 int minVal[MAX_N + 1][2];
178 memset(maxEdgeInPath, 0, sizeof(maxEdgeInPath));
179 memset(conDirectToRoot, 0, sizeof(conDirectToRoot));
180 memset(minVal, 0, sizeof(minVal));
181 int root = getIndex("Park");
182 int conn = solveMST(root);
183 int i, c;
184 //选择root和每一个连通分量之间权值最小的边及权值
185 for(i = 0; i < nodesn; i++)
186 {
187 int w;
188 if(i == root || (w = nodes[root].con[i]) == 0) continue;
189 int c = color[i];
190 if(minVal[c][1] == 0 || w < minVal[c][1])
191 {
192 minVal[c][0] = i;
193 minVal[c][1] = w;
194 }
195 }
196 //链接root与conn个连通分量间具有最小权值的边
197 for(c = 1; c <= conn; c++)
198 {
199 int to = minVal[c][0];
200 int w = minVal[c][1];
201 conDirectToRoot[to] = true; //标记直连
202 graph[root][to] = graph[to][root] = w; //连边
203 }
204
205 //添加额外的kdeg - conn条边
206 int time = kdeg - conn;
207 while(time--)
208 {
209 memset(maxEdgeInPath, 0, sizeof(maxEdgeInPath));
210
211 getMaxEdgeInPath(root, maxEdgeInPath);
212 int minVal, minNode, maxsubval = 0;
213
214 //遍历所有节点,寻找具有最大权值差的点minNode
215 for(int k = 0; k < nodesn; k++)
216 {
217 int w;
218 if((w = nodes[root].con[k]) == 0 || conDirectToRoot[k]) continue;
219 if((maxEdgeInPath[k][2] - w) > maxsubval)
220 {
221 maxsubval = maxEdgeInPath[k][2] - w;
222 minVal = w;
223 minNode = k;
224 }
225 }
226 //无法再优化,则退出
227 if(maxsubval == 0)
228 break;
229 //更换边
230 int f = maxEdgeInPath[minNode][0], t = maxEdgeInPath[minNode][1];
231 graph[f][t] = graph[t][f] = 0;
232 graph[root][minNode] = graph[minNode][root] = minVal;
233 }
234
235 }
236 int main()
237 {
238 int in, i, j, w;
239 string from, to;
240 init(); //初始化
241 cin>>in;
242 for(i = 0; i < in; i++)
243 {
244 cin>>from>>to>>w;
245 processNodes(from, to, w);
246 }
247 cin>>kdeg;
248 sort(edges, edges + edgen, cmp);
249 solveKDegreeContraintTree();
250 int res = 0;
251 for(i = 0; i < nodesn; i++)
252 for(j = i + 1; j < nodesn; j++)
253 res += graph[i][j];
254 printf("Total miles driven: %d\n", res);
255 return 0;
256 }
posted @ 2011-08-26 15:37  我们一直在努力  阅读(255)  评论(0编辑  收藏  举报