我在比赛的某个地方发现了这个问题,而且还没有能够提出解决方案。
N个城市的坐标为(x,y)。我必须从头开始 城市到达第二个城市。每个城市都有一个加油站。 所以我必须找到最小量的气体容器才能到达 最后的城市。 例如:
Input:
3
17 4
19 4
18 5
Output:
1.414
在这里,我的方式是:1->3->2
我使用简单的强力方法,但速度很慢。如何优化我的代码? 也许有更好的解决方案?
#include <iostream>
#include <algorithm>
#include <stack>
#include <math.h>
#include <cstring>
#include <iomanip>
#include <map>
#include <queue>
#include <fstream>
using namespace std;
int n, used[203];
double min_dist;
struct pc {
int x, y;
};
pc a[202];
double find_dist(pc a, pc b) {
double dist = sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) );
return dist;
}
void functio(double d, int used[], int k, int step) {
used[k] = 1;
if(k == 1) {
if(d < min_dist) {
min_dist = d;
}
used[k] = 0;
return;
}
for(int i = 1; i < n; ++i) {
if(i != k && used[i] == 0) {
double temp = find_dist(a[k], a[i]);
if(temp > d) {
if(temp < min_dist)
functio(temp, used, i, step + 1);
}
else {
if(d < min_dist)
functio(d, used, i, step + 1);
}
}
}
used[k] = 0;
}
int main() {
cin >> n;
for(int i = 0; i < n; ++i)
cin >> a[i].x >> a[i].y;
min_dist = 1000000;
memset(used, 0, sizeof(used));
functio(0, used, 0, 0);
cout << fixed << setprecision(3) << min_dist << endl;
}
答案 0 :(得分:3)
最小生成树具有编码顶点之间所有路径的整洁属性,可最小化路径上最长边的长度。对于Euclidean MST,您可以计算Delaunay三角剖分,然后运行您最喜欢的O(m log n)时间算法(在m = O(n)边的图上),总运行时间为O(n log n)。或者,您可以使用具有良好常量的O(n ^ 2)-time算法运行具有天真优先级队列的Prim(特别是如果您利用SIMD)。
答案 1 :(得分:1)
因此,您在算法中尝试优化的是您在两个城市之间旅行的最长距离。因为那是你的油箱需要的大小。 这是最短路径的变体,因为您正在尝试优化enire路径长度。
我认为你可以逃脱这个:
制作边列表。 (每对城市之间的距离)
从列表中删除最长边,除非这会导致目标无法访问。
一旦您无法移除最长的路径,这意味着这是您前往目的地的限制因素。其余的路线不再重要了。
然后最后你应该有一个边缘列表,它构成了源和目的地之间的路径。
我没有证明这个解决方案是最优的,所以没有保证。但请考虑一下:如果你删除最长的路径,只有较短的路径,所以最大的腿距不会增加。
关于复杂性,时间复杂度为O(n log n)
,因为您必须对边缘进行排序
内存复杂度为O(n ^ 2)
这可能不是最有效的算法,因为它是一种图算法,并没有使用城市在欧几里德平面上的事实。那里可能有一些优化......
答案 2 :(得分:1)
您可以使用二进制搜索将时间复杂度降低到O(n^2*log(n))
,这将在1秒的时间限制内运行。二元搜索背后的想法是,如果我们可以使用x
卷从城市1到达城市2,则无需检查更高容量的容器。如果我们无法使用此功能,那么我们需要超过x
音量。要检查我们是否可以使用x卷访问城市2,您可以使用BFS
。如果两个城市之间的距离相距x
,那么它可以从一个城市移动到另一个城市,我们可以说它们是通过边缘连接的。
代码:
int vis[203];
double eps=1e-8;
struct pc {
double x, y;
};
double find_dist(pc &a, pc &b) {
double dist=sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
return dist;
}
bool can(vector<pc> &v, double x) { // can we reach 2nd city with volume x
int n=v.size();
vector<vector<int>> graph(n, vector<int>(n, 0)); // graph in adjacency matrix form
// set edges in graph
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
if(i==j) continue; //same city
double d=find_dist(v[i], v[j]);
if(d<=x) graph[i][j]=1; // can reach from city i to city j using x volume
}
}
// perform BFS
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(0); // we start from city 0 (0 absed index)
vis[0]=1;
while(!q.empty()) {
int top=q.front();
q.pop();
if(top==1) return true; // can reach city 2 (1 in 0-based index)
for(int i=0; i<n; i++) {
if(top!=i && !vis[i] && graph[top][i]==1) {
q.push(i);
vis[i]=1;
}
}
}
return false; // can't reach city 2
}
double calc(vector<pc> &v) { // calculates minimum volume using binary search
double lo=0, hi=1e18;
while(abs(hi-lo)>eps) {
double mid=(lo+hi)/2;
if(can(v, mid)) {
hi=mid; // we need at most x volume
} else{
lo=mid; // we need more than x volumer
}
}
return lo;
}