両端キュー アルゴリズム 2019. トラクター

トピック

一日中働いた後、農夫のジョンはトラクターを畑の真ん中に置き忘れたことをすっかり忘れていました。

彼の牛はとてもやんちゃで、ジョンにいたずらしようと決めました。

彼らは N 俵の干し草を畑のさまざまな場所に置いたので、ジョンはトラクターを追い払う前に干し草の俵の一部を取り除く必要がありました。

トラクターの位置と N 個の干し草の位置は、2 次元平面上の整数の座標点です。

トラクターの初期位置には干し草の俵はありません。

ジョンがトラクターを運転するとき、トラクターは座標軸 (北、南、東、西) に平行な方向にのみ移動でき、トラクターは毎回整数の距離を移動する必要があります。

たとえば、トラクターを運転すると、まず北に 2 ユニット、次に東に 3 ユニット移動します。

トラクターは干し草の俵が置かれている位置には移動できません。

ジョンが 2 次元平面の原点までトラクターを運転できるように、取り除く必要がある干し草の俵の最小数を決定するのを手伝ってください。

入力形式
最初の行には、N とトラクターの初期位置 (x,y) の 3 つの整数が含まれます。
次の N 行には、各行に干し草の俵の位置座標 (x, y) が含まれています。

出力形式
John が取り除く必要がある干し草の俵の最小数を出力します。

データ範囲
1≤N≤50000、1≤x
,y≤1000

入力例:

7 6 3
6 2
5
2
4 3 2 1
7 3
5 4
6 4

出力サンプル:

1

アイデアの分析

質問を読む → 抽象的な質問タイプは行列 → 共通モデルに変換 - 最短パス

この問題は、ダイクストラと両端キューを組み合わせて使用​​することで解決できます。

①両端キューのすべての点から原点までの距離はいつでも最大で 2 つの端であり、2 つのセグメント間の差はわずか 1 です。数学的帰納法を使用して次のことを証明します。 ②質問の意味がわかり
ます
ここに画像の説明を挿入します
。マップは任意のサイズ上を歩くことができ1000*1000、アルゴリズムを設計するときに移動するエリアを として指定できるため、その周囲を歩くこともできます1001*1001

実装:

  • マトリクスの範囲を1002*1002(1001*1001も原理的には可能ですが、計算上問題があるため適宜増やしてください)とすると、マトリクスの上部と右側の最外周のバリアフリーを満足することができます。
  • マトリックスの横断は0最初から開始されます (干し草の山は1最初から配置されます)。これにより、マトリックスの下部と左側の部分のバリアフリーの最外周を満たすことができます。

ここに画像の説明を挿入します

コード

#include<iostream>
#include<cstring>
#include<algorithm>
#include<deque> //双端队列的头文件

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;
const int N = 1002;//定义矩阵边长

bool g[N][N];   //记录位置上是否有障碍物(有:true  无:flase)
bool st[N][N];  //判端是否走过此处(走过:true  无:false)
int dist[N][N];//最短路径距离

int bfs(int sx, int sy){
    
    
    
    deque<PII> q;//定义双端队列
    q.push_back({
    
    sx, sy});//起点加到双端队列
    memset(dist, 0x3f, sizeof dist);//把距离初始化成正无穷 
    dist[sx][sy] = 0;
    
    int dx[4] = {
    
    -1, 0, 1, 0}, dy[4] = {
    
    0, 1, 0, -1};//顺序:上右下左
     
    while(q.size()){
    
    //当队列不空
        auto t = q.front();//取出队头元素
        q.pop_front();//删除队头元素、
        
        if(st[t.x][t.y])continue;//判断当前点是否被搜过 
        st[t.x][t.y] = true;//判断当前点是否被搜过 
        
        if(!t.x && !t.y)break;//判断当前点是否被搜过 
        
        for(int i = 0; i < 4; i++){
    
    
            int x = t.x + dx[i], y = t.y + dy[i];//求当前方向坐标
            if(x >= 0 && x < N && y >= 0 &&y < N){
    
    
                int w = g[x][y]==1 ?1:0;//如果是障碍物,权值置为1 ,否则置为0
                //int w = 0;
                //if (g[x][y]) w = 1;
                if(dist[x][y] > dist[t.x][t.y] + w){
    
    //如果距离能被更新且比原有距离更短
                    dist[x][y] = dist[t.x][t.y] + w;//更新权值
                    if(!w) q.push_front({
    
    x,y});//加到队头
                    else q.push_back({
    
    x, y});//加到队尾
                }
            }
        }
    }
    
    return dist[0][0];
}


int main(){
    
    
    int n, sx, sy;//n是障碍物数量,sx,sy是起点
    scanf("%d%d%d", &n, &sx, &sy);
    while(n--){
    
    
        int x, y;
        scanf("%d%d", &x, &y);//读入障碍物的坐标
        g[x][y] = true;
    }
    printf("%d\n",bfs(sx,sy));//输出距离原点最短距离 
    
    return 0;
}

お役に立てば幸いです、いいねとコメントをお願いします~


おすすめ

転載: blog.csdn.net/smile66688/article/details/122859175