1. 程式人生 > 其它 >CSP202009-4 星際旅行

CSP202009-4 星際旅行

技術標籤:練習題目演算法c++資料結構

CSP202009-4 星際旅行

題目

這道題的題目可以在CSP官網中可以看到喲!

演算法思想

這道題可以將距離和拆分成每兩個點之間的距離,以簡化問題。因此需要判斷兩點之間的連線是否與中心的黑洞圓有交點,如果沒有交點,則兩點之間最短的距離就是兩點之間連線的距離;如果有交點,則說明兩點之間最短距離肯定是要包含圓的一部分的。兩點之間的直線距離通過距離公式即可直接求出,而中心圓的部分則需要相關數學幾何的知識即可求出。總體來看,這道題難度不大,大家可以嘗試一下喲!
結果

程式碼詳解

預處理

按照輸入格式,將輸入資訊讀取出來,具體程式碼如下:

int i, j, k;
	cin >> n >> m >> r;
	for (i = 1; i <= n; i++)   //中心原點的N維座標
		cin >> o[i];
	for (i = 1; i <= m; i++)
	{
		double x = 0.0;
		for (j = 1; j <= n; j++)
		{
			cin >> pos[i][j];
			x = x + (pos[i][j] - o[j]) * (pos[i][j] - o[
j]); } dis[i] = sqrt(x); //點與中心原點之間的距離 d[i] = sqrt(x - r * r); //過該點的切線弦的長度 }

2、最短距離的計算

這一部分是整道題演算法的核心,包含判斷兩點之間的連線是否與中心的黑洞圓有交點,如果沒有交點,則兩點之間最短的距離就是兩點之間連線的距離;如果有交點,則說明兩點之間最短距離肯定是要包含圓的一部分的。兩點之間的直線距離通過距離公式即可直接求出,而中心圓的部分則需要相關數學幾何的知識即可求出。
具體程式碼如下:

for (i = 1; i <= m; i++)
	{
		for (j = i +
1; j <= m; j++) { double distance = 0.0; for (k = 1; k <= n; k++) distance = distance + (pos[i][k] - pos[j][k]) * (pos[i][k] - pos[j][k]); double x = sqrt(distance); double p = (dis[i] + dis[j] + x) / 2; double s = sqrt(p * (p - x) * (p - dis[i]) * (p - dis[j])); double h = 2 * s / x; if (h >= r) { ans[i][j] = x; ans[j][i] = x; } else { if (dis[i] * dis[i] >= x * x + dis[j] * dis[j] || dis[j] * dis[j] >= x * x + dis[i] * dis[i]) { ans[i][j] = x; ans[j][i] = x; } else { double angle = acos((dis[i] * dis[i] + dis[j] * dis[j] - x * x) / (2 * dis[i] * dis[j])); double angle1 = acos(r / dis[i]); double angle2 = acos(r / dis[j]); ans[i][j] = r * (angle - angle1 - angle2) + d[i] + d[j]; ans[j][i] = r * (angle - angle1 - angle2) + d[i] + d[j]; } } } }

3、輸出

統計每一個節點與其他節點的最短距離的和,輸出即可,具體程式碼如下:

for (i = 1; i <= m; i++)
	{
		double sum = 0.0;
		for (j = 1; j <= m; j++)
		{
			if (i == j) continue;
			sum = sum + ans[i][j];
		}
		printf("%.14lf", sum); 
		cout << endl;
	}
	return 0;

完整程式碼

#include<iostream>
#include<cstdio>
#include<cmath>
#pragma warning (disable:4996)
using namespace std;
int n, m, r;
int o[200];
int pos[5000][200];
double dis[5000]; //節點與原點之間的距離
double d[5000];   //節點切線弦的長度
double ans[5000][5000]; //存放任意兩點之間的最短距離
int main()
{
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
	int i, j, k;
	cin >> n >> m >> r;
	for (i = 1; i <= n; i++)
		cin >> o[i];
	for (i = 1; i <= m; i++)
	{
		double x = 0.0;
		for (j = 1; j <= n; j++)
		{
			cin >> pos[i][j];
			x = x + (pos[i][j] - o[j]) * (pos[i][j] - o[j]);
		} 
		dis[i] = sqrt(x);        //點與中心原點之間的距離
		d[i] = sqrt(x - r * r);  //過該點的切線弦的長度
	}
	for (i = 1; i <= m; i++)
	{
		for (j = i + 1; j <= m; j++)
		{
			double distance = 0.0;
			for (k = 1; k <= n; k++)
				distance = distance + (pos[i][k] - pos[j][k]) * (pos[i][k] - pos[j][k]);
			double x = sqrt(distance);
			double p = (dis[i] + dis[j] + x) / 2;
			double s = sqrt(p * (p - x) * (p - dis[i]) * (p - dis[j]));
			double h = 2 * s / x;
			if (h >= r)
			{
				ans[i][j] = x;
				ans[j][i] = x;
			}
			else
			{
				if (dis[i] * dis[i] >= x * x + dis[j] * dis[j] || dis[j] * dis[j] >= x * x + dis[i] * dis[i])
				{
					ans[i][j] = x;
					ans[j][i] = x;
				}
				else
				{
					double angle = acos((dis[i] * dis[i] + dis[j] * dis[j] - x * x) / (2 * dis[i] * dis[j]));
					double angle1 = acos(r / dis[i]);
					double angle2 = acos(r / dis[j]);
					ans[i][j] = r * (angle - angle1 - angle2) + d[i] + d[j];
					ans[j][i] = r * (angle - angle1 - angle2) + d[i] + d[j];
				}
			}
		}
	}
	for (i = 1; i <= m; i++)
	{
		double sum = 0.0;
		for (j = 1; j <= m; j++)
		{
			if (i == j) continue;
			sum = sum + ans[i][j];
		}
		printf("%.14lf", sum); 
		cout << endl;
	}
	return 0;
}