CSP202009-4 星際旅行
阿新 • • 發佈:2021-02-01
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;
}