查找覆盖有相同半径圆

时间:2016-06-16 10:13:23

标签: algorithm geometry dynamic-programming computational-geometry

我在接受采访时被问到这个问题而我无法解决。

如果你能帮助我解决它,我将非常感激。

问题如下: -

您将获得矩形区域,其左侧和最底层坐标 (0,0)正确最最顶层坐标为(x,y)

' r'

您目前正站在(0,0),想要触及(x,y)而不触及任何圆圈。

你必须告诉它是否可能。

他告诉我你可以自由地在 2点之间移动,没有必要沿着 x或y轴移动。

我想到的解决方案涉及采用 x * y 维度的矩阵,并且对于每个圆圈,标记位于其中的点或触摸它。

之后,从(0,0)开始应用BFS,检查我们是否可以达到(x,y)

他告诉我BFS是错的,我无法弄清楚原因。

我假设圆圈有整数半径并且整数坐标

他还要求我在没有这些假设的情况下解决问题。

我无法做到。当被问到时,他告诉我这是一个标准问题而且我应该能够在Google上找到它

我再也不能了。请帮忙!

7 个答案:

答案 0 :(得分:3)

面试官错误的是BFS无法使用。每当你进入一个单元格时,检查单元格是否在一个圆圈内,通过检查单元格与你可用的每个其他圆心的距离,如果它在dist< = R内,则无法从该单元格到达目前的特定细胞。我解决了采访中出现的类似问题 - https://www.interviewbit.com/problems/valid-path/ 代码很简单 -

   public class Solution {
private class Pair
{
    int x ; int y ;
}
ArrayList<Integer> xindex ; ArrayList<Integer> yindex ; int R ;int len ;
public String solve(int x, int y, int n, int r, ArrayList<Integer> xi, ArrayList<Integer> yi) {
    int dp[][] = new int[x+1][y+1] ;
    len = xi.size() ;
    for(int i=0;i<=x;i++)
    {
        for(int j=0;j<=y;j++)
        dp[i][j] = -1 ;
    }

    xindex = xi ; yindex = yi ;
    dp[0][0] = 1 ; R = r*r ;
    LinkedList<Pair> q = new LinkedList<Pair>() ;
    Pair obj = new Pair() ;
    obj.x = 0 ; obj.y = 0 ;
    q.add(obj) ;
    int arr1[] = {1,1,1,0,-1,-1,-1,0} ;
    int arr2[] = {-1,0,1,1,1,0,-1,-1} ;

    while(q.size()!=0)
    {
        Pair temp = q.poll() ;
        int x1 = temp.x ;
        int x2 = temp.y ;

        for(int i=0;i<8;i++)
        {
            int t1 = x1+arr1[i] ; int t2 = x2+arr2[i] ;

            if((t1>=0)&&(t1<=x)&&(t2>=0)&&(t2<=y))
            {
                if(dp[t1][t2]==-1)
                {
                    boolean res = isValidIndex(t1,t2) ;
                    if(res==false)
                    dp[t1][t2] = 2 ;
                    else
                    {
                        dp[t1][t2] = 1 ;
                        Pair t = new Pair() ;
                        t.x = t1 ; 
                        t.y = t2 ;
                        q.add(t) ;
                    }
                }
            }
        }

        if(dp[x][y]!=-1)
        break ;
    }

    if(dp[x][y]==1)
    return "YES" ;

    return "NO" ;

}

public boolean isValidIndex(int x,int y)
{
    for(int i=0;i<len;i++)
    {
        int x1 = xindex.get(i) ; int x2 = yindex.get(i) ;
        if((x==x1)&&(y==x2))
        return false ;

        int n = (x1-x)*(x1-x) + (x2-y)*(x2-y) ;

        if(n<=R)
        return false ;
    }
    return true ;
}

}

答案 1 :(得分:2)

如果两个圆圈正在接触,则在它们的中心之间绘制一条线段。如果圆形接触矩形的边缘,则将其中心与最近侧的投影相连。然后丢弃圈子。这并没有改变障碍物的连接性,你已经将问题转化为平面直线细分中更为家庭化的问题。

enter image description here

一种方法可以是通过分解板中的域,即通过每个中心绘制水平线以在梯形中划分平面。然后通过种子填充方法,可以确定起始板并扩展与其具有共同水平面的板的可达性,直到填充封闭区域或到达出口板。

下面是从左上方的板坯中填充种子的中间步骤。

enter image description here

如果圆心位于规则网格上,则可以进行标准种子填充。

答案 2 :(得分:1)

我认为如果它们的中心之间的距离小于2r,则2个圆圈只能阻挡路径。所以它应该足以构建重叠圆的“岛”,并检查是否有任何岛阻挡从0到(x,y)的路径,即它是否有任何圆与矩形边界相交,使得这些交叉点之间的直线相交点会挡住路径。

答案 3 :(得分:1)

解决此问题的最佳方法是使用dfs搜索。首先让我们考虑一些基本情况,比如是否存在包含两个点中的任何一个(即0,0或x,y)的圆,但不是两个都是,那么答案是&#34; NO&#34;如果存在包含两个点的圆圈,那么我们可以从圆圈列表中删除它。现在我们留下的圆圈不包含这两个点中的任何一个,现在使用这些圆心作为顶点绘制图形,如果它们之间的距离小于或等于2 * R,则连接任意两个顶点还为所有圆保持一个掩模阵列,掩模存储由特定圆切割的边,即如果我们将左垂直边编号为0顶水平边作为1右垂直边作为2而底部水平边作为3然后在掩模中对应于a特定圆圈那些位将是活动的,对应于由该圆圈切割的边。 现在只需执行一个dfs并查看图中是否存在一条路径,该路径显示是否可以使用图形边缘从(0到2或0到3或1到2或1到2)移动(我们用掩码来检查)。如果存在这样的路径,那么回答是&#34;否&#34;否则答案总是&#34;是&#34;。

答案 4 :(得分:1)

我按照安东建议的确切方式做了这个问题。使用DSU制造所谓的岛屿。然后确定以下条件:TB,LR,TR,LB(T:顶部,B:底部,L:左,R:右)交叉点。如果任何一个岛屿形成了这些交叉点,它们肯定会阻挡这条路径,答案就是“不”。 问题可以在采访位找到: https://www.interviewbit.com/problems/valid-path/ 这里给出了相应的解决方案:

http://ideone.com/19iSOn

#include<bits/stdc++.h>
#include<unordered_set>
using namespace std;

class Solution{
public:
    string solve(int A, int B, int C, int D, vector<int> &E, vector<int> &F);
};

#define pii pair<int,int>

int par[1000+5];
int rnk[1000+5];
bool vis[1000+5];

void initialise(){
    for(int i=0;i<=1000;i++){
        par[i]=i;
        rnk[i]=1;
        vis[i]=false;
    }
}

int findPar(int node){
    if(par[node]==node)return node;
    return par[node]=findPar(par[node]);
}

void makeUnion(int a,int b){
    int parA=findPar(a);
    int parB=findPar(b);

    if(parA==parB)return;
    if(rnk[parA]<rnk[parB])par[parB]=parA;
    else if(rnk[parB]<rnk[parA])par[parA]=parB;
    else{
        rnk[parA]++;
        par[parB]=parA;
    }
}


bool findBlockage(int root,int X,int Y,int N,int R,vector<pair<int,pii>>vec){
    int top=0;
    int bottom=INT_MAX;
    int left=INT_MAX;
    int right=0;

    for(int i=0;i<N;i++){
        if(par[vec[i].first]==root){
            int x=vec[i].second.first;
            int y=vec[i].second.second;
            top=max(top,y+R);
            bottom=min(bottom,y-R);
            left=min(left,x-R);
            right=max(right,x+R);
        }
    }
    if(top>=Y and bottom<=0)return true;
    if(right>=X and left<=0)return true;
    if(top>=Y and right>=X)return true;
    if(left<=0 and bottom<=0)return true;
    return false;
}

string Solution::solve(int X, int Y, int N, int R, vector<int> &E, vector<int> &F) {
    vector<pair<int,pii>> vec;
    int id=0;
    for(int i=0;i<N;i++){
        vec.push_back({id,{E[i],F[i]}});
        id++;
    }

    initialise();

    for(int i=0;i<N;i++){
        for(int j=i;j<N;j++){
            if(i==j)continue;
            int x1=vec[i].second.first;
            int x2=vec[j].second.first;

            int y1=vec[i].second.second;
            int y2=vec[j].second.second;

            if(((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= (4*R*R)){
                makeUnion(vec[i].first,vec[j].first);
            }
        }
    }

    for(int i=0;i<N;i++){
        if(!vis[par[vec[i].first]]){
            vis[par[vec[i].first]]=1;
            bool ret = findBlockage(par[vec[i].first],X,Y,N,R,vec);
            if(ret)return "NO";
        }
    }
    return "YES";
}

int main(){
    int n,x,y,r;
    cin>>x>>y>>n>>r;
    vector<int>X(n);
    vector<int>Y(n);

    for(int i=0;i<n;i++)cin>>X[i];
    for(int i=0;i<n;i++)cin>>Y[i];

    Solution sol;
    cout<<sol.solve(n,x,y,r,X,Y)<<endl;
}

答案 5 :(得分:0)

懒惰 方法:

  1. 轮流参观每个球
    • 如果它没有碰到任何其他球,请将其废弃。
    • 如果它接触到另一个,请将其添加到另一个您喜欢的节点图系统,并在它们之间创建一个连接(做一些内务处理以避免重复)。
  2. 创建额外球A,B,C,D
  3. 在A和触及左边缘的所有球之间,B和触及顶边的所有球之间创建额外的连接(图中的线)等。
  4. 询问你的A *是否愿意导航你从A到C / A到D / B再到C / B到D.
  5. 如果对上述任何一项是肯定的,那么Q的答案是否定的。又快又脏: - )。
  6. enter image description here

答案 6 :(得分:0)

使用简单的DP概念针对此问题的递归解决方案(以圆为障碍物,找到从[0,0][x,y]的路径)

public class Solution {
    public long radiusSquare;
    public int xDest, yDest;
    boolean vis[][];
    public final static int[] xDelta = new int[]{0, 1, -1, 0, 1, -1, -1, 1};
    public final static int[] yDelta = new int[]{1, 0, 0, -1, 1, -1, 1, -1};

    public String solve(int x, int y, int radius, ArrayList<Integer> X, ArrayList<Integer> Y) {
        xDest = x; yDest = y;
        radiusSquare = radius*radius;
        int dp[][] = new int[x+1][y+1]; // = 0 (not visited), = 1 (a valid point), = 2 (invalid)
        vis = new boolean[x+1][y+1];
        if (recur(0, 0, X, Y, dp)) return "YES";
        return "NO";
    }
    public boolean recur(int xi, int yi, ArrayList<Integer> X, 
                         ArrayList<Integer> Y, int dp[][]){
        if (xi == xDest && yi == yDest) return true;
        if(vis[xi][yi]) return false; // already processed coordinate
        vis[xi][yi] = true;
        for (int i =0; i < xDelta.length; i++){
            int xArg = xi+xDelta[i];
            int yArg = yi+yDelta[i];
            if (validCoordinates(xArg, yArg, X, Y, dp) && recur(xArg, yArg, X, Y, dp)) 
                return true;
        }
        return false;
    }
    public boolean validCoordinates(int x, int y, ArrayList<Integer> X, ArrayList<Integer> Y, int dp[][]){
        if (x < 0 || y < 0 || x > xDest || y > yDest) return false;

        if (dp[x][y] != 0){
            if (dp[x][y] == 1) return true; // valid coord 
            if (dp[x][y] == 2) return false;
        } 

        for (int i = 0; i < X.size(); i++){ // loop through each circle.
            long sumOfSquare = ((x-X.get(i))*(x-X.get(i))) + ((y-Y.get(i))*(y-Y.get(i)));
            if (sumOfSquare <= radiusSquare){
                dp[x][y] = 2; // comes on or inside circle
                return false;
            }
        }
        dp[x][y] = 1;
        return true;
    }
}