POJ 3625 Building Roads 解题报告
2009-08-04 15:36
302 查看
题意:给出N个坐标点的位置,其中的K个是已经相连的,求把它们连在一起需要最短的路径和。
分析:典型的最小生成树。一开始我选择了Kruskal(我也不知道怎么会选上的。。)。把所有有可能的边全部添加进去,外加stl的heap优化。
后来在discuss发现用朴素的prim便能达到很高的效率了,于是,再写了一个版本。
不仅效率高了,编程复杂度还降了下来。
下次记住了:Kruskal O(E*lg(v))
Prim O(E+V*lg(V))
稠密图使用Prim,Kruskal使用在稀疏图
分析:典型的最小生成树。一开始我选择了Kruskal(我也不知道怎么会选上的。。)。把所有有可能的边全部添加进去,外加stl的heap优化。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <iostream> #include <algorithm> #include <string> #include <map> #include <vector> using namespace std; #define dis(x1,y1,x2,y2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) struct Edge { int u,v; double w; //由于stl的heap是最大堆,所以这里重载小于号为大于号 //就能使heap变为最小堆 bool operator<(const Edge &x) { return w > x.w; } }; Edge edge[600000]; double x[1100],y[1100]; int p[1100]; //查找最高父节点 int par(int x) { if(p[x] < 0) return x; return (p[x] = par(p[x])); } //合并节点 int join(int x,int y) { int xx,yy; xx = par(x); yy = par(y); if(xx != yy) if(p[xx] < p[yy]) { p[xx] += p[yy]; p[yy] = xx; } else { p[yy] += p[xx]; p[xx] = yy; } } int main() { int n,m,last; scanf("%d%d",&n,&m); last = n-1; for(int i = 1; i <= n; i++) scanf("%lf%lf",x+i,y+i); memset(p,-1,sizeof(p)); int xx,yy; for(int i = 0; i < m; i++) { scanf("%d%d",&xx,&yy); //将一开始就连在一起的节点合并 if(par(xx) != par(yy)) { join(xx,yy); last--; } } int pn(0); for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++) { edge[pn].u = i; edge[pn].v = j; edge[pn++].w = dis(x[i],y[i],x[j],y[j]); } //用heap必先make_heap make_heap(edge,edge+pn); double res(0.0); int u,v; double w; while(last) { u = edge[0].u; v = edge[0].v; w = edge[0].w; if(par(u) != par(v)) { join(u,v); res += w; last--; } //弹出最小值边 pop_heap(edge,edge+pn); pn--; } printf("%.2f/n",res+10e-5); return 0; } //8524K 125MS G++ 1456B
后来在discuss发现用朴素的prim便能达到很高的效率了,于是,再写了一个版本。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <iostream> #include <algorithm> #include <string> #include <map> #include <vector> using namespace std; #define D(x1,y1,x2,y2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) const int N = 1100; double dis ,x ,y ; bool v ; int main() { int n,m,u,tx,ty; double least ,res,_min; bool v ; memset(v,false,sizeof(v)); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%lf%lf",x+i,y+i); for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++) dis[i][j] = dis[j][i] = D(x[i],y[i],x[j],y[j]); for(int i = 0; i < m; i++) { scanf("%d%d",&tx,&ty); dis[tx][ty] = dis[ty][tx] = 0.0; } for(int i = 1; i <= n; i++) least[i] = dis[1][i]; v[1] = true; res = 0.0; for(int i = 1; i < n; i++) { _min = 0x7fffffff; for(int j = 2; j <= n; j++) if(!v[j] && least[j] < _min) { _min = least[j]; u = j; } v[u] = true; res += _min; for(int j = 2; j <= n; j++) if(!v[j] && dis[u][j] < least[j]) least[j] = dis[u][j]; } printf("%.2f/n",res); return 0; } //9312K 94MS G++ 1134B
不仅效率高了,编程复杂度还降了下来。
下次记住了:Kruskal O(E*lg(v))
Prim O(E+V*lg(V))
稠密图使用Prim,Kruskal使用在稀疏图
相关文章推荐
- poj3625 解题报告
- POJ 1003 Hangover [解题报告] Java
- poj解题报告——1035
- POJ 1423 解题报告
- POJ 4047 Garden (线段树 - 区间增减、区间查询) -- 解题报告
- 解题报告:POJ_3460&HDU_1685 Booksort IDA*
- POJ 1006 Biorhythms [解题报告] Java
- POJ 1001 解题报告
- POJ2739解题报告
- POJ 3126解题报告
- 简单动态规划(POJ 1609 Tiling Up Blocks 解题报告)
- poj-openjudge 1042:Moles 解题报告
- POJ-1988-Cube Stacking 解题报告
- poj1753解题报告(1):DFS算法
- poj1142 解题报告
- LA-3399 & POJ-2739 Sum of Consecutive Prime Numbers 解题报告
- POJ1250解题报告
- POJ3619解题报告
- POJ3602解题报告
- POJ 2243解题报告