1. 程式人生 > >牛客國慶集訓派對Day1___L New Game!——最短路

牛客國慶集訓派對Day1___L New Game!——最短路

題目連結:傳送門

題目大意:

    給出兩條平行線和nn個圓,計算從一條線走到另一條線所消耗的體力。同時,在線上、圓上、園內走不消耗體力,求體力的最小花費。

解題思路:

    一開始沒想到是最短路,後來仔細一想,除了最短路也沒啥其他的了。將線和圓都想象成一個個點,每個點之間的距離滿足以下關係: LL11LL22 之間連邊權值C1C2A2+B2\frac{| C_1- C_2 |} {\sqrt{A^2 + B^2}}LL與圓ii之間連邊權值max(0,d(Oi,L1)ri)max(0, d(O_i,L_1)-r_i)

Oi,L1)ri)ii與圓jj之間連邊權值 max(0,d(Oi,Oj)rirj)max(0, d(O_i,O_j)-r_i-r_j) 最後求最短路即可

程式碼思路:

    注意要用double,double的絕對值是fabs函式

核心:將線和圓看成一個個點來建圖,靈活地運用最短路知識

#include<bits/stdc++.h>
using namespace std;

const int N = 1005;
const double INF= 1e10+10;
int m, n, vis[N];
double dis[N], mp[N][N];

struct node{
    double x, y, r;
}cc[1005];

void init() {
	for (int i=0; i<=n+1; i++)
		for (int j=0; j<=n+1; j++) {
			if (i == j)	mp[i][j] = 0;
			else mp[i][j] = INF;
		}
}

void creatgraph() {
	double a, b, c1, c2;
	scanf("%lf%lf%lf%lf", &a, &b, &c1, &c2);
	for(int i=1; i<=n; i++)
		scanf("%lf%lf%lf", &cc[i].x, &cc[i].y, &cc[i].r);
	mp[0][n+1] = mp[n+1][0] = fabs(c1-c2) / sqrt(a*a+b*b);
	for(int i=1; i<=n; i++)
	{
		double tp = fabs(cc[i].x*a+cc[i].y*b+c1) / sqrt(a*a+b*b) - cc[i].r;
		if(tp<1e-4) tp=0;
		mp[0][i] = mp[i][0] = tp;
		tp = fabs(cc[i].x*a+cc[i].y*b+c2) / sqrt(a*a+b*b) - cc[i].r;
		if(tp<1e-4) tp=0;
		mp[n+1][i] = mp[i][n+1] = tp;
	}
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
		{
			if(i==j) continue;
			double tp = fabs(cc[i].x-cc[j].x)*fabs(cc[i].x-cc[j].x) + \
						fabs(cc[i].y-cc[j].y)*fabs(cc[i].y-cc[j].y);
			tp = sqrt(tp) - cc[i].r - cc[j].r;
			if(tp <= 1e-4) tp = 0;
			mp[i][j] = mp[j][i] = tp;
		}
}

void dijkstra(int start) {
	for (int i=0; i<=n+1; i++)
		dis[i] = mp[start][i];
	memset(vis, 0, sizeof(vis));
	vis[start] = 1;
	for (int i=1; i<=n; i++) {	
		/*找出離起點最近的點*/
		double minn = INF;
		int k = -1;
		for (int j=0; j<=n+1; j++) {
			if (!vis[j] && dis[j]<minn) {
				minn = dis[j];
				k = j;
			}
		}
		vis[k] = 1;
		for (int j=0; j<=n+1; j++) {	//鬆弛操作,找到媒介使得出現新的最短路
			if (!vis[j] && mp[k][j] < INF)
				dis[j] = min(dis[j], dis[k] + mp[k][j]);
		}
	}
}

int main() {

	scanf("%d", &n);	//n個頂點
	init();	//初始化地圖
	creatgraph();	//建圖
	dijkstra(0);	//核心迪傑斯特拉演算法
	printf("%.6f", dis[n+1]);	//輸出最短路結果

	return 0;
}