我们有一组 F 的 n 个二维飞盘。我们想将 F 划分为两个子集 F1 和 F2,以便在每个子集中没有两个飞盘相交。我们的函数接受这样的输入:(x_j, y_j) 是第 j 个飞盘的中心,rad_j 是第 j 个飞盘的半径。输出应为 s_0 s_1 ... s_n-1,其中如果第 j 个飞盘在 F1 中,则 s_j = 1,如果第 j 个飞盘在 F2 中,则 s_i = 2。如果不能对 F 进行分区,则返回 0。理想情况下,算法应在 O(n^2) 时间内计算。
我认为我应该使用某种类型的矩阵表示形式来表示这种图形,但后来我认为我不需要构建图形,但我认为 BFS/DFS 会很有用,但我坚持如何在 O(n^2) 中优雅地做到这一点。顺便说一句,我正在用 C++ 编写代码。
最佳答案
您在图形搜索方面走在了正确的轨道上。这是一个 C++11、O(V^2)、使用 O(V+E) 空间的深度优先搜索解决方案。
DFS 本身的时间复杂度为 O(V+E),但生成邻接表的时间复杂度为 O(V^2)。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
struct Frisbee
{
double x;
double y;
double radius;
};
int dfs(const vector< vector<int> > &adj, vector<int> &p, int last_ind, int curr_ind)
{
if (p[curr_ind]) // node already painted
{
if (p[last_ind] == p[curr_ind]) // painted same color as neighbor -> failure
return 0;
return 1; // painting is compatible
}
// node not yet painted
p[curr_ind] = (1 == p[last_ind] ? 2 : 1); // paint opposite color as neighbor
for (int j = 0; j < adj[curr_ind].size(); ++j)
if (!dfs(adj, p, curr_ind, adj[curr_ind][j])) // dfs on neighbors
return 0;
return 1;
}
int partition(const vector<Frisbee> &F, vector<int> &p)
{
// compute adjacency lists
vector< vector<int> > adj(F.size());
p.resize(F.size());
for (int i = 0; i < F.size(); ++i)
{
p[i] = 0;
for (int j = i + 1; j < F.size(); ++j)
{
double dist = sqrt((F[i].x - F[j].x) * (F[i].x - F[j].x) + (F[i].y - F[j].y) * (F[i].y - F[j].y));
if (dist < F[i].radius + F[j].radius)
{
adj[i].push_back(j);
adj[j].push_back(i);
}
}
}
// find starting points for dfs
for (int i = 0; i < F.size(); ++i)
if (0 == p[i]) // node i not yet painted
{
p[i] = 1; // arbitrarily choose initial color
for (int j = 0; j < adj[i].size(); ++j)
if (!dfs(adj, p, i, adj[i][j])) // dfs on neighbors
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
vector<Frisbee> F = { { 1.0, 1.0, 1.0 }, { 2.0, 2.0, 1.0 }, { -1.0, -1.0, 1.0 }, { -2.0, -2.0, 1.0 }, { 5.0, 5.0, 1.0 }, { -5.0, 5.0, 1.0 } };
vector<int> p;
if (partition(F, p))
{
for (size_t i = 0; i < F.size(); ++i)
cout << p[i] << " ";
cout << endl;
}
else
cout << "No partition possible!" << endl;
F.push_back({ 1.5, 1.5, 1.0 }); // add a 3-way intersection
if (partition(F, p))
{
for (size_t i = 0; i < F.size(); ++i)
cout << p[i] << " ";
cout << endl;
}
else
cout << "No partition possible!" << endl;
return 0;
}
这是输出(在略有不同的飞盘组上的两个分区):
1 2 1 2 1 1
No partition possible!
关于c++ - 分区飞盘 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29091411/