c++ - 分区飞盘 C++

标签 c++ algorithm graph set

我们有一组 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/

相关文章:

algorithm - 用 1 种颜色对图表进行部分着色

r - 手动计算接近度并与 R 中的 igraph 包进行比较

c++ - 哪种数据结构类似于双向链表和数组的组合?

c++ - Long 变量到 char 数组

c++ - Vim、C++、YCM 和 Syntastic 包含路径问题

c - 矩形相交算法

c++ - 初始化宽字符数组

java - 该算法最坏情况下的时间复杂度是多少?

algorithm - 标记与未标记二叉树?

c++ - 将字符串拆分为邻接矩阵索引