algorithm - Facebook 黑客杯 : After the Dance Battle

标签 algorithm graph-theory

我们想在一个特殊的网格中找到两点之间的最短路径。我们可以一次在相邻的方格之间移动,但我们也可以一次移动在相同类型的单元格(有 10 种类型)之间移动,无论它们之间的距离有多远。

对于最大 100x100 的网格,我们如何找到在两点之间行进所需的步数?

最佳答案

我在比赛中使用 BFS 解决了这个问题。

问题可以建模为图形。每个单元格都是一个节点,并且与每个相邻单元格都有一条边。我们可以通过根据需要计算网格坐标来访问每个单元格及其相邻单元格,而不是显式构建图形,从而简单地保持图形隐式。

每个单元格也有一条到所有相同颜色单元格的边。我们可以通过保留每种颜色的单元格列表并访问与当前单元格颜色相同的所有单元格来将其添加到我们的图形中。

Dijkstra 或 A* 之类的东西可以工作(毕竟它们本质上是一个具有优先级队列/启发式的 BFS),但为这样一个简单的问题实现它会严重矫枉过正。

代码如下(C++):

#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map> 

using namespace std;

char grid[101][101];
int cost[101][101];

vector<pair<int,int> > colour[10]; // lists of same coloured cells

//used to compute adjacent cells
int dr[]={ 0, 0, 1,-1};
int dc[]={ 1,-1, 0,0};

int rows,cols; // total rows and coloumns


int bfs(pair<int,int> start){
    memset(cost,-1,sizeof(cost)); // all unvisited nodes have negative cost to mark them
    cost[start.first][start.second]=0; // start node has cost 0

    queue<pair<int,int> > Q;
    Q.push(start);

    while (!Q.empty()){

        pair<int,int> node=Q.front();Q.pop();
        int r=node.first;
        int c=node.second;
        int cst=cost[r][c];
        if (grid[r][c]=='E'){
            return cst;
        }

        // search adjacent cells
        for(int i=0;i<4;i++){
            int nr=r+dr[i];
            int nc=c+dc[i];
            if (nr>=0 && nr<rows && nc>=0 && nc<cols && cost[nr][nc]<0 && grid[nr][nc]!='W'){
                cost[nr][nc]=cst+1;
                Q.push(make_pair(nr,nc));
            }
        }

        // search cells of the same colour
        if (grid[r][c]>='1' && grid[r][c]<='9'){
            vector<pair<int,int> > &trans=colour[grid[r][c]-'0'];
            for(int i=0;i<trans.size();i++){
                pair<int,int> next=trans[i];
                if (cost[next.first][next.second]<0){
                    cost[next.first][next.second]=cst+1;
                    Q.push(next);
                }
            }
        }
    }
    return -1;
}

int main(){
    int N;
    cin>>N;
    while(N--){
        cerr<<"cases left"<<N<<endl;
        cin>>rows>>cols;
        pair<int,int> start;
        for(int i=0;i<10;i++) colour[i].clear();

        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                cin>>grid[i][j];

                if (grid[i][j]=='S'){
                    start=make_pair(i,j);
                }
                else if (grid[i][j]>='1' && grid[i][j]<='9'){
                    colour[grid[i][j]-'0'].push_back(make_pair(i,j));
                }
            }
        }
        cout<<bfs(start)<<"\n";
    }

    return 0;
}

关于algorithm - Facebook 黑客杯 : After the Dance Battle,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4701330/

相关文章:

algorithm - 查找树中两个给定顶点之间路径的最有效方法

将图划分为组的算法

ruby - 可能效率低下的算法

javascript - 每个簇选取 m 个点

algorithm - n 和一个精确整数的嵌套 for 循环的复杂性?

image - 位图匹配(或二维数组)的高效算法?

c++ - 防止在递归组合生成中分配内存

algorithm - 从每条边中选择一个顶点

algorithm - 遍历非汉密尔顿、未加权、无向图中的所有顶点

c++ - 子三角形中最大元素的总和