先贴出我错误的代码,我思路就错了,这道题明显不是0节点到1节点的距离最小,而是0到1的过程中每一步跳跃中的最大值要尽可能的小。所以解题的思路不是Dijkstra而是最小生成树。
错误代码:
#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的根节点是相同的,也就是他们已经属于一个大集合了为结束条件,此时所选择的边为最终的结果。