[Luoguのp1141] 01迷路

ポータル

フェイス質問

タイトル説明

デジタルだけが存在する\(0 \)及び(\ 1)\からなる\(N \ n倍\)グリッド迷路は。あなたが格子0上に配置されている場合は、隣接して移動することができる\(4 \)細胞中の細胞\(1 \)同じ、グリッド1である場合は、隣接して移動することができる\ (4 \)格子グリッド\(0 \)に。

あなたの仕事は次のとおりです。与えられた迷路の問い合わせのために(それ自身を含む)のグリッドの数に1つのセルから移動を開始することができます。

入出力フォーマット

入力形式

\(1 \) 2つの正の整数の挙動\(N、M \)

ここで\(N- \)行は、各列\(N- \)文字が、文字のみであることができる(0 \)\または\(1 \)文字の間にスペースを含みません。

次に、\(\ m)の行は、各列\(2 \) 空間正の整数で区切られた\(I、J \) 最初の迷路に対応する\(I \)\(J \)カラム最初から移動することができ、グリッドは、どのくらいこのグリッドセルを依頼します。

出力フォーマット

\(M \)ライン、回答を対応する各クエリの出力。

サンプル入力と出力

入力#1:

2 2
01
10
1 1
2 2

出力#1:

4
4

説明/ヒント

サンプルについて、互いにまでのすべてのグリッド。

(20 \%\)\、データ(\ 10 \ルN-)\

(40 \%\)\、データ(\ 50 \ルN-)\

以下のための\(50 \%\)データ、\(M \ル5 \。)

(60 \%\)\データ、\(\ル100、M \ル100 \ N-)

以下のための\(100 \%\)データ、\(N- \ 1000年ル、M \ 100000ル\)

分析

この質問は非常に単純な検索ように見えますが、データの範囲のこの質問を見て、私たちは、この質問は実際に流血されていることがわかります。そして、水Niwaiの最近の検索は、この質問を見て、私は突然アイデアが来た:缶互いに素セットそれを行うには?
かもしれない、それは我々が、我々はマップを構築することができ、通信をブロックする可能性があることは明らかです。直接利用するために我々はすでによく配置されていると信じるに一次元二次元マップ(i,j)にマッピングされi*n+j、シンプルで原油を。
そして、私が言いたい、私はあまり言わないよセットの詳細を確認互いに素セットは本当に世界でのデータ構造の中で最も美しいです。
その時、私は通常の2次元アレイに使用dfsラン互いに素なセットを、結果MLE3点が作られた70ポイント良好な結果我々は互いに素-セットで、配列にマップをスクロールすることができ、それは簡単なことです。特定のコードで参照してください。
MLE

コード

付けdfsのバージョンでは、このバージョンで私が得たことに注目すべき70ポイントを、ダイレクトコピーを取ってはいけませんそれから私は、空間的複雑に注意を払う必要があり、これはレッスンああです。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2020-02-19 23:01:54 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-02-19 23:41:37
 */

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 1005;
const int maxn2 = 1000005;

int n;
int fa[maxn2],u[maxn2];
bool a[maxn][maxn];
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1}; 

int find(int x){//查
    return fa[x] == x?x:fa[x] = find(fa[x]);
}

void merge(int a,int b){//并
    int fa1 = find(a), fa2 = find(b);
    if(fa1 != fa2){
        u[fa1] += u[fa2];
        fa[fa2] = fa[fa1];
    }
}

// 以上都是并查集的板子,这里不再多说。

bool valid(int x,int y){
    return x>0&&x<=n&&y>0&&y<=n;
}//边界判断。

int dfs(int x,int y){
    int ind = x*n+y;//映射处理
    if(fa[ind] != -1) return find(ind);//记忆化
    fa[ind] = ind;
    u[ind] = 1;
    //初始化

    for(int i=0;i<4;i++){
        int nxtx = x+dx[i], nxty = y+dy[i];//枚举下一种情况的x坐标和y坐标。
        if(valid(nxtx,nxty) && a[x][y]!=a[nxtx][nxty])//合法。
            merge(ind,dfs(nxtx,nxty));//并。
    }
    
    return find(ind);//回溯
}

int main(){
    int T;
    scanf("%d%d",&n,&T);
    memset(fa,-1,sizeof(fa));
    for(int i = 1; i <= n ;i++)
        for(int j = 1; j <= n; j++)
            scanf("%1d",&a[i][j]);

    while(T--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",u[dfs(x,y)]);
    }
    return 0;
}

うちACコード(ローリングアレイ)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 1005;
const int maxn2 = 1000005;

int n;
int fa[maxn2],u[maxn2];
char a[2][maxn];

int find(int x){
    return fa[x] == x?x:fa[x] = find(fa[x]);
}

void merge(int a,int b){
    int fa1 = find(a), fa2 = find(b);
    if(fa1 != fa2){
        u[fa1] += u[fa2];
        fa[fa2] = fa[fa1];
    }
}

int main(){
    int T;
    scanf("%d%d",&n,&T);
    memset(fa,-1,sizeof(fa));
    for(int i = 0; i < n; i++){
        scanf("%s",a[i&1]);//读入
        for(int j = 0; j < n; j++){
            int ind = i*n+j;//映射
            fa[ind] = ind;
            u[ind] = 1;
            if(i && a[(i-1)&1][j] !=a[i&1][j]) merge(ind-n,ind);//横向并
            if(j && a[i&1][j-1] != a[i&1][j]) merge(ind,ind-1);//纵向并
        }
    }

    while(T--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",u[find(x*n-n+y-1)]);
        //这里蟹蟹懒。这里的原型应该是(x-1)*n+y-1,就是用了个乘法分配。
    }
    return 0;
}

評価結果

MLE 70R30836609
AC 100R30837084

over.

おすすめ

転載: www.cnblogs.com/crab-in-the-northeast/p/luogu-p1141.html