题目链接:http://poj.org/problem?id=1751 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1048
题目大意:
给定n个点的坐标。还有m对已经相连的点的编号。求连接这n个点的总权值最小的一棵生成树,输出还需要连接的点的编号。
题目思路:
这道题目和以前做过的poj2421是一样的。这里采用了那篇博客里面的第一种方法。幸运的是,在poj上1A了。但是在zoj上,因为输入输出格式有一些不一样,卡了一下,到最后我也没明白“If no new highways need to be built (all towns are already connected), then the output should be created but it should be empty.” 这句话的含义,看书上的翻译是,如果不需要再建了,输出一个空行。可是,在poj上,输出空行与否都是可以过的。在zoj上,输出空行就WA了,就是因为这个错误……
poj代码:
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 = 759; 23 double edge[MAX][MAX]; 24 double lowcost[MAX];int nearvex[MAX]; 25 int n, m; 26 typedef struct Point { 27 int x, y; 28 }Point; 29 Point point[MAX]; 30 void prim(int u0) { 31 int i, j, k, v;double sum = 0; 32 for (i = 1; i <= n; ++i) { 33 lowcost[i] = edge[i][u0]; nearvex[i] = u0; 34 } 35 lowcost[u0] = 0; nearvex[u0] = -1; 36 for (i = 1; i < n; ++i) { 37 double min = 1.0*MAXN;int v = -1; 38 for (j = 1; j <= n; ++j) { 39 if (nearvex[j] != -1 && lowcost[j] < min) { 40 min = lowcost[j]; v = j; 41 } 42 } 43 if (v != -1){ 44 if (lowcost[v] != 0) { 45 printf("%d %d\n", v, nearvex[v]); 46 } 47 sum += lowcost[v]; nearvex[v] = -1; 48 for (j = 1; j <= n; ++j) { 49 if (nearvex[j] != -1 && edge[v][j] < lowcost[j]) { 50 lowcost[j] = edge[v][j]; nearvex[j] = v; 51 } 52 } 53 } 54 } 55 if (sum == 0) printf("\n\n"); 56 } 57 int main(void){ 58 #ifndef ONLINE_JUDGE 59 freopen("poj1751.in", "r", stdin); 60 #endif 61 while (~scanf("%d", &n)) { 62 int i, j, k; 63 for (i = 1; i <= n; ++i) { 64 scanf("%d%d", &point[i].x, &point[i].y); 65 } 66 for (i = 1; i <= n; ++i) { 67 for (j = i+1; j <= n; ++j) { 68 int x1, y1; x1 = point[i].x-point[j].x; 69 y1 = point[i].y-point[j].y; 70 edge[j][i]=edge[i][j] = sqrt(pow(x1,2.0)+pow(y1,2.0)); 71 } 72 } 73 scanf("%d", &m); 74 int a, b; 75 for (i = 1; i <= m; ++i) { 76 scanf("%d%d", &a, &b); 77 edge[a][b] = edge[b][a] = 0; 78 } 79 prim(1); 80 } 81 82 return 0; 83 }
zoj代码:
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 = 759; 23 double edge[MAX][MAX]; 24 double lowcost[MAX];int nearvex[MAX]; 25 int n, m; 26 typedef struct Point { 27 int x, y; 28 }Point; 29 Point point[MAX]; 30 void prim(int u0) { 31 int i, j, k, v;double sum = 0; 32 for (i = 1; i <= n; ++i) { 33 lowcost[i] = edge[i][u0]; nearvex[i] = u0; 34 } 35 lowcost[u0] = 0; nearvex[u0] = -1; 36 for (i = 1; i < n; ++i) { 37 double min = 1.0*MAXN;int v = -1; 38 for (j = 1; j <= n; ++j) { 39 if (nearvex[j] != -1 && lowcost[j] < min) { 40 min = lowcost[j]; v = j; 41 } 42 } 43 if (lowcost[v] != 0) { 44 printf("%d %d\n", v, nearvex[v]); 45 } 46 sum += lowcost[v]; nearvex[v] = -1; 47 for (j = 1; j <= n; ++j) { 48 if (nearvex[j] != -1 && edge[v][j] < lowcost[j]) { 49 lowcost[j] = edge[v][j]; nearvex[j] = v; 50 } 51 } 52 } 53 } 54 int main(void){ 55 #ifndef ONLINE_JUDGE 56 freopen("poj1751.in", "r", stdin); 57 #endif 58 int t; scanf("%d", &t); 59 while (t--) { 60 scanf("%d", &n); 61 int i, j, k; 62 for (i = 1; i <= n; ++i) { 63 scanf("%d%d", &point[i].x, &point[i].y); 64 } 65 for (i = 1; i <= n; ++i) { 66 for (j = i+1; j <= n; ++j) { 67 int x1, y1; x1 = point[i].x-point[j].x; 68 y1 = point[i].y-point[j].y; 69 edge[j][i]=edge[i][j] = (pow(x1,2.0)+pow(y1,2.0)); 70 } 71 } 72 scanf("%d", &m); 73 int a, b; 74 for (i = 1; i <= m; ++i) { 75 scanf("%d%d", &a, &b); 76 edge[a][b] = edge[b][a] = 0; 77 } 78 prim(1); 79 if (t!=0) printf("\n"); 80 } 81 82 return 0; 83 }
另外,还有一个小trick,因为不需要求最后的权值,我求的距离的作用是标记一下是不是到最后都不需要再建了,来决定是不是需要输出空行,虽然现在赶脚这个很多余……o(╯□╰)o 所以呢,注意到坐标范围是在10000以内,所以可以省掉sqrt()也不会溢出,就省去了开方的运算,直接用平方和表征距离,这样不就可以节省点儿时间了么……O(∩_∩)O哈哈~