1. 程式人生 > >New Game!(牛客賽)——Dijkstra最短路徑

New Game!(牛客賽)——Dijkstra最短路徑

題目描述

Eagle Jump公司正在開發一款新的遊戲。Hifumi Takimoto作為其中的員工,獲得了提前試玩的機會。現在她正在試圖通過一個迷宮。 這個迷宮有一些特點。為了方便描述,我們對這個迷宮建立平面直角座標系。迷宮中有兩條平行直線 L1:Ax+By+C1=0, L2:Ax+By+C2=0,還有 n 個圓 。角色在直線上、圓上、園內行走不消耗體力。在其他位置上由S點走到T點消耗的體力為S和T的歐幾里得距離。 Hifumi Takimoto想從 L1 出發,走到 L2 。請計算最少需要多少體力。

輸入描述:

第一行五個正整數 n,A,B,C1,C2 (1≤ n ≤ 1000, -10000 ≤ A,B,C1,C2 ≤ 10000),其中 A,B 不同時為 0。
接下來 n 行每行三個整數 x,y,r(-10000 ≤ x,y ≤ 10000, 1≤ r ≤ 10000) 表示一個圓心為 (x,y),半徑為 r 的圓。

輸出描述:

僅一行一個實數表示答案。與正確結果的絕對誤差或者相對誤差不超過 10-4 即算正確。

示例1

輸入

2 0 1 0 -4
0 1 1
1 3 1

輸出

0.236068

程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<math.h>
using namespace std;

struct Circle {
	double x;
	double y;
	double r;
};

int n;
double A, B, C1, C2;
Circle cir[1001];

//-----------------------Dijkstra------------------
struct Edge {
	int v;
	double w;
	int next;
};

int p[2000];
Edge e[2000000];
int eid;

void init() {
	memset(p, -1, sizeof(p));
	eid = 0;
}

void Insert(int u, int v, double w) {
	e[eid].v = v;
	e[eid].w = w;
	e[eid].next = p[u];
	p[u] = eid++;
}

typedef pair<int, int> PII;

set<PII, less<PII>> min_heap;

double dist[2000];    //儲存單源最短路徑
int vis[2000];     //標記每個頂點是否被選取

bool dijkstra(int s) {
	//初始化
	memset(vis, 0, sizeof(vis));
	//memset(dist, 0x3f, sizeof(dist));
	for (int i = 0; i < 2000; i++) {
		dist[i] = 100000000;
	}

	min_heap.insert(make_pair(0, s));
	dist[s] = 0;
	for (int i = 0; i < n+2; ++i) {
		if (min_heap.size() == 0) {
			return false;
		}

		auto iter = min_heap.begin();
		int v = iter->second;
		min_heap.erase(*iter);
		vis[v] = 1;

		for (int j = p[v]; j != -1; j = e[j].next) {
			int x = e[j].v;
			if (!vis[x] && dist[v] + e[j].w < dist[x]) {
				min_heap.erase(make_pair(dist[x], x));
				dist[x] = dist[v] + e[j].w;
				min_heap.insert(make_pair(dist[x], x));
			}
		}
	}
	return true;
}

//--------------------------------------------------

int main() {

	cin >> n >> A >> B >> C1 >> C2;
	for (int i = 0; i < n; i++) {
		cin >> cir[i].x >> cir[i].y >> cir[i].r;
	}

	init();
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			double dis = sqrt(
				(cir[i].x - cir[j].x)*(cir[i].x - cir[j].x) 
				+ (cir[i].y - cir[j].y)*(cir[i].y - cir[j].y)
			) - cir[i].r - cir[j].r;
			if (dis < 0) {
				Insert(i + 1, j + 1, 0);
				Insert(j + 1, i + 1, 0);
			}
			else {
				Insert(i + 1, j + 1, dis);
				Insert(j + 1, i + 1, dis);
			}
		}
	}
	for (int i = 0; i < n; i++) {
		double dis = abs(A * cir[i].x + B * cir[i].y + C1) / sqrt(A*A + B*B) - cir[i].r;
		if (dis < 0) {
			Insert(i + 1, n + 1, 0);
			Insert(n + 1, i + 1, 0);
		}
		else {
			Insert(i + 1, n + 1, dis);
			Insert(n + 1, i + 1, dis);
		}
	}
	for (int i = 0; i < n; i++) {
		double dis = abs(A * cir[i].x + B * cir[i].y + C2) / sqrt(A*A + B*B) - cir[i].r;
		if (dis < 0) {
			Insert(i + 1, n + 2, 0);
			Insert(n + 2, i + 1, 0);
		}
		else {
			Insert(i + 1, n + 2, dis);
			Insert(n + 2, i + 1, dis);
		}
	}
	Insert(n + 1, n + 2, abs(C1 - C2) / sqrt(A*A + B*B));
	Insert(n + 2, n + 1, abs(C1 - C2) / sqrt(A*A + B*B));

	dijkstra(n + 1);
	cout << dist[n + 2] << endl;

	return 0;
}