文章标题
2017-06-23 18:36
218 查看
先贴出我错误的代码,我思路就错了,这道题明显不是0节点到1节点的距离最小,而是0到1的过程中每一步跳跃中的最大值要尽可能的小。所以解题的思路不是Dijkstra而是最小生成树。
错误代码:
正确代码之Prime:
Accepted 332K 16MS
正确代码之Kruskal (union-find):
Accepted 396K 32MS
解释一下注释的那个地方为什么改成了find(1)==find(2),因为如果仅仅单纯看是否1和2已经在集合中了是不对的,应该以1的根节点和2的根节点是相同的,也就是他们已经属于一个大集合了为结束条件,此时所选择的边为最终的结果。
错误代码:
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<math.h> #include<algorithm> #include<memory.h> #include<vector> #include<queue> #include<map> #define MAXNUM 210 #define INF 100000; using namespace std; int N, Point[MAXNUM][2], record[MAXNUM]; float W[MAXNUM][MAXNUM], dis[MAXNUM]; bool mark[MAXNUM]; float ComputeDis(int x, int y) { float tmp; tmp = (Point[x][0] - Point[y][0])*(Point[x][0] - Point[y][0]) + (Point[x][1] - Point[y][1])*(Point[x][1] - Point[y][1]); tmp = sqrt(tmp); return tmp; } float Dijkstra() { int i, j, k, t; float tmp; for (i = 0; i < N; i++) dis[i] = INF; dis[0] = 0; t = 0; for (i = 0; i < N; i++) { tmp = INF; for (j = 0; j < N; j++) { if (!mark[j] && tmp>dis[j]) { tmp = dis[j]; k = j; } } mark[k] = true; record[t++] = k; for (j = 0; j < N; j++) { if (!mark[j] && dis[j]>dis[k] + W[k][j]) { dis[j] = dis[k] + W[k][j]; } } } memset(mark, 0, sizeof(mark)); tmp = INF; i = 1; while (i != 0) { for (j = 0; j < N; j++) { if (!mark[j] && dis[i] == dis[j] + W[j][i]) { mark[j] = 1; tmp = min(tmp, W[j][i]); i = j; break; } } } return tmp; } int main() { freopen("1.txt", "r", stdin); int i, j, Cases; float weight, ans; Cases = 1; while (scanf("%d", &N) != EOF&& N) { for (i = 0; i < N; i++) { scanf("%d%d", &Point[i][0], &Point[i][1]); } for (i = 0; i < N; i++) for (j = i + 1; j < N; j++) { weight = ComputeDis(i, j); W[i][j] = weight; W[j][i] = weight; } for (i = 0; i < N; i++) W[i][i] = 0; memset(mark, 0, sizeof(mark)); printf("Scenario #%d\n", Cases++); printf("Frog Distance = %.3f\n", Dijkstra()); } }
正确代码之Prime:
Accepted 332K 16MS
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<math.h> #include<algorithm> #include<memory.h> #include<vector> #define MAXNUM 210 #define INF 100000; using namespace std; int N, Point[MAXNUM][2]; float W[MAXNUM][MAXNUM]; bool mark[MAXNUM]; float ComputeDis(int x, int y) { float tmp; tmp = (Point[x][0] - Point[y][0])*(Point[x][0] - Point[y][0]) + (Point[x][1] - Point[y][1])*(Point[x][1] - Point[y][1]); tmp = sqrt(tmp); return tmp; } float Prime() { int i, j, k, a, b; float tmp, ans; vector<int> set; mark[0] = 1; ans = 0; set.push_back(0); for (i = 1; i < N; i++) { tmp = INF; for (j = 0; j < set.size(); j++) { for (k = 1; k < N; k++) { if (!mark[k] && tmp>W[set[j]][k]) { tmp = W[set[j]][k]; a = set[j]; b = k; } } } ans = max(ans, W[a][b]); if (b == 1) { break; } mark[b] = 1; set.push_back(b); } return ans; } int main() { //freopen("1.txt", "r", stdin); int i, j, Cases; float weight, ans; Cases = 1; while (scanf("%d", &N) != EOF&& N) { for (i = 0; i < N; i++) { scanf("%d%d", &Point[i][0], &Point[i][1]); } for (i = 0; i < N; i++) for (j = i + 1; j < N; j++) { weight = ComputeDis(i, j); W[i][j] = weight; W[j][i] = weight; } for (i = 0; i < N; i++) W[i][i] = 0; memset(mark, 0, sizeof(mark)); printf("Scenario #%d\n", Cases++); printf("Frog Distance = %.3f\n", Prime()); printf("\n"); } }
正确代码之Kruskal (union-find):
Accepted 396K 32MS
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<math.h> #include<algorithm> #include<memory.h> #define MAXNUM 210 #define INF 100000; using namespace std; int N, Point[MAXNUM][2], Pre[MAXNUM]; bool mark[MAXNUM]; struct Edge { int start, end; float cost; }Path[MAXNUM*MAXNUM]; bool cmp(Edge a1, Edge a2) { return a1.cost < a2.cost; } float ComputeDis(int x, int y) { float tmp; tmp = (Point[x][0] - Point[y][0])*(Point[x][0] - Point[y][0]) + (Point[x][1] - Point[y][1])*(Point[x][1] - Point[y][1]); tmp = sqrt(tmp); return tmp; } int find(int i) { while (Pre[i] != i) i = Pre[i]; return i; } void Union(int a,int b) { int x, y; x = find(a); y = find(b); if (x != y) Pre[y] = x; } float Kruskal(int t) { int i, j, k; float ans = 0; bool Freddy, Fiona; Freddy = Fiona = 0; for (i = 0; i < t; i++) { if (find(Path[i].start) != find(Path[i].end)) { Union(Path[i].start, Path[i].end); ans = max(ans, Path[i].cost); //if (Path[i].start == 0 || Path[i].end == 0) //Freddy = 1; //if (Path[i].start == 1 || Path[i].end == 1) //Fiona = 1; } //if (Fiona&&Freddy) //break; if (find(0) == find(1)) break; } return ans; } int main() { freopen("1.txt", "r", stdin); int i, j, t, Cases; float weight, ans; Cases = 1; while (scanf("%d", &N) != EOF&& N) { for (i = 0; i < N; i++) { scanf("%d%d", &Point[i][0], &Point[i][1]); } t = 0; for (i = 0; i < N; i++) for (j = i + 1; j < N; j++) { Path[t].cost = ComputeDis(i, j); Path[t].start = i; Path[t++].end = j; } sort(Path, Path + t, cmp); for (i = 0; i < N; i++) Pre[i] = i; memset(mark, 0, sizeof(mark)); printf("Scenario #%d\n", Cases++); printf("Frog Distance = %.3f\n", Kruskal(t)); printf("\n"); } }
解释一下注释的那个地方为什么改成了find(1)==find(2),因为如果仅仅单纯看是否1和2已经在集合中了是不对的,应该以1的根节点和2的根节点是相同的,也就是他们已经属于一个大集合了为结束条件,此时所选择的边为最终的结果。