POJ-2253 Frogger 最短路
该题就是求一只青蛙从1号石头跳到2号石头的所有路径中跳跃距离最大值的最小值。仔细想想的话,将原来dijkstra的dis数组赋值为这个minmax含义,同样满足贪心规则,所以就是普通的dijkstra。
代码如下:
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #define MAXN 205 using namespace std; int N; struct Node { int x, y; }e[MAXN]; double G[MAXN][MAXN], dis[MAXN]; // 定义dis数组用来保留minmax值,且该值满足贪心规则 int hash[MAXN]; inline double dist(int x, int y) { return sqrt(double((e[x].x-e[y].x)*(e[x].x-e[y].x)+(e[x].y-e[y].y)*(e[x].y-e[y].y))); } double dijkstra() { int pos; double Min; fill(dis, dis+MAXN, 9999999999.); memset(hash, 0, sizeof (hash)); dis[1] = 0; // 到达第一号石头所需要的mm值为0 hash[1] = 1; for (int i = 1; i <= N; ++i) { pos = 1, Min = 9999999999.; for (int j = 1; j <= N; ++j) { if (!hash[j] && Min - dis[j] > 1e-6) { pos = j; Min = dis[j]; } } hash[pos] = 1; if (pos == 2) { return dis[2]; } for (int j = 1; j <= N; ++j) { double t = max(dis[pos], G[pos][j]); if (!hash[j]) { dis[j] = min(dis[j], t); } } } } int main() { int ca = 0; while (scanf("%d", &N), N) { memset(G, 0, sizeof (G)); for (int i = 1; i <= N; ++i) { scanf("%d %d", &e[i].x, &e[i].y); } for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { G[i][j] = dist(i, j); } } printf("Scenario #%d\n", ++ca); printf("Frog Distance = %.3lf\n\n", dijkstra()); } return 0; }
kruskal版本
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define MAXN 205 using namespace std; int N, pos, set[MAXN]; struct Node { int x, y; double far; bool operator < (Node t) const { return far < t.far; } }e[40005]; struct { int x, y; }p[205]; inline double dist(int x, int y) { return sqrt(double((p[x].x-p[y].x)*(p[x].x-p[y].x) + (p[x].y-p[y].y)*(p[x].y-p[y].y))); } int find(int x) { return set[x] = set[x] == x ? x : find(set[x]); } inline void merge(int a, int b) { set[a] = b; } int main() { int ca = 0; while (scanf("%d", &N), N) { pos = 0; for (int i = 1; i <= N; ++i) { scanf("%d %d", &p[i].x, &p[i].y); set[i] = i; } for (int i = 1; i <= N; ++i) { for (int j = i+1; j <= N; ++j) { ++pos; e[pos].x = i, e[pos].y = j; ++pos; e[pos].x = j, e[pos].y = i; e[pos].far = e[pos-1].far = dist(i, j); } } sort(e+1, e+1+pos); for (int i = 1; i <= pos; ++i) { int a = find(e[i].x), b = find(e[i].y); if (a != b) { merge(a, b); } if (find(1) == find(2)) { printf("Scenario #%d\n", ++ca); printf("Frog Distance = %.3lf\n\n", e[i].far); break; } } } return 0; }
dfs版本
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define MAXN 205 #define INF 29999999. using namespace std; int N, head[MAXN], pos; double dis[MAXN]; struct { int x, y; }p[205]; struct edge { int num, next; double far; }e[40005]; inline double dist(int x, int y) { return sqrt(double((p[x].x-p[y].x)*(p[x].x-p[y].x) + (p[x].y-p[y].y)*(p[x].y-p[y].y))); } void insert(int x, int y) { ++pos; e[pos].next = head[x]; e[pos].num = y; e[pos].far = dist(x, y); head[x] = pos; } void dfs(int x, double far) { if (x == 2) { return; } for (int i = head[x]; i; i = e[i].next) { double t = max(e[i].far, far); if (dis[e[i].num]-t > 1e-6) { dis[e[i].num] = t; dfs(e[i].num, dis[e[i].num]); } } } int main() { int ca = 0; while (scanf("%d", &N), N) { pos = 0; fill(dis, dis+MAXN, INF); memset(head, 0, sizeof (head)); for (int i = 1; i <= N; ++i) { scanf("%d %d", &p[i].x, &p[i].y); } for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { insert(i, j); } } dis[1] = 0.; dfs(1, dis[1]); printf("Scenario #%d\n", ++ca); printf("Frog Distance = %.3lf\n\n", dis[2]); } return 0; }
Floyd版本
#include <cstdlib> #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> using std::max; using std::min; using std::cin; using std::cout; using std::endl; int N; struct Node { int x, y; }e[205]; double G[205][205]; double dist(const Node & a, const Node & b) { return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); } void build() { for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { G[i][j] = dist(e[i], e[j]); } } } void floyd() { for (int k = 1; k <= N; ++k) { for (int i = 1; i <= N; ++i) { if (i == k) continue; for (int j = 1; j <= N; ++j) { if (G[i][k] > G[i][j] || G[k][j] > G[i][j] || j == k) continue; G[i][j] = min(G[i][j], max(G[i][k], G[k][j])); } } } } int main () { int ca = 0; while (cin >> N, N) { for (int i = 1; i <= N; ++i) { cin >> e[i].x >> e[i].y; } build(); floyd(); printf("Scenario #%d\n", ++ca); printf("Frog Distance = %.3f\n\n", G[1][2]); } return 0; }
SPFA版本
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #define INF 999999999. #define MAXN 205 using namespace std; // 该题每两点之间都有边的存在,所以这里用SPFA遍历边的时候并没有什么优势 int N, head[MAXN], pos; double dis[MAXN]; struct Node { int x, y; }e[MAXN]; struct Edge { int num, next; double far; }edge[40005]; double dist(int x, int y) { return sqrt(double((e[x].x-e[y].x)*(e[x].x-e[y].x)+(e[x].y-e[y].y)*(e[x].y-e[y].y))); } void insert(int x, int y) { ++pos; edge[pos].next = head[x]; edge[pos].num = y; edge[pos].far = dist(x, y); head[x] = pos; }double SPFA() { int obj; queue<int>q; fill(dis, dis+MAXN, INF); dis[1] = 0; q.push(1); while (!q.empty()) { obj = q.front(); q.pop(); for (int i = head[obj]; i; i = edge[i].next) { double t = max(dis[obj], edge[i].far); if (t < dis[edge[i].num]) { dis[edge[i].num] = t; q.push(edge[i].num); } } } return dis[2]; } int main() { int ca = 0; while (scanf("%d", &N), N) { memset(head, 0, sizeof (head)); pos = 0; // 由于是静态的边,所以这里需要回溯pos指针 for (int i = 1; i <= N; ++i) { scanf("%d %d", &e[i].x, &e[i].y); } for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { insert(i, j); } } printf("Scenario #%d\n", ++ca); printf("Frog Distance = %.3lf\n\n", SPFA()); } return 0; }