zoukankan      html  css  js  c++  java
  • P1141 01迷宫 DFS (用并查集优化)

      

    题目描述

    有一个仅由数字00与11组成的n imes nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。

    你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

    输入输出格式

    输入格式:

    11行为两个正整数n,mn,m。

    下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。

    接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。

    输出格式:

    mm行,对于每个询问输出相应答案。

    输入输出样例

    输入样例#1: 复制
    2 2
    01
    10
    1 1
    2 2
    
    输出样例#1: 复制
    4
    4
    

    说明

    所有格子互相可达。

    对于20\%20%的数据,n≤10n10;

    对于40\%40%的数据,n≤50n50;

    对于50\%50%的数据,m≤5m5;

    对于60\%60%的数据,n≤100,m≤100n100,m100;

    对于100\%100%的数据,n≤1000,m≤100000n1000,m100000。

    非常好的一道搜索题!!!!

    看似很简单的一题   但是没有经过优化的算法有三个点会TLE    正好用来加深对搜索的理解:

    一开始DFS TLE三个点

    后来    开一个和mp一样大的ans数组 每次DFS完后进行储存答案   还是TLE     这也是意料之中的  毕竟每次都要遍历1000^2 来储存答案肯定超时

    这时候需要一个更好的方法存答案

    将更新ans数组放在dfs的return前面    是错的 可能更新的时候cnt并没有累合完毕  

    一种可行的方法是将dfs再增加一个标记维度    正好用循环i来充当标记非常巧妙!

    代码: 500ms

    #include<bits/stdc++.h>
    using namespace std;
    //input
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m);
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define N 1005
    int n,m;
    char mp[N][N];
    int vis[N][N];
    int cnt;
    int ans[100*N];
    
    bool inmap(int x,int y)
    {
        return x>=1&&y>=1&&x<=n&&y<=n;
    }
    
    int dx[4]={0,1,0,-1};
    int dy[4]={1,0,-1,0};
    
    void dfs(int x,int y,char val,int flag)
    {
        vis[x][y]=flag;
        ans[flag]++;
        rep(i,0,3)
        {
            int a=x+dx[i];
            int b=y+dy[i];
            if(!vis[a][b]&&inmap(a,b)&&mp[a][b]!=val )
                dfs(a,b,mp[a][b],flag);
        }
        return ;
    }
    
    int main()
    {
        RII(n,m);
        rep(i,1,n)
        RS(mp[i]+1);
        rep(i,1,m)
        {
            int x,y;
            RII(x,y);
            if(!vis[x][y])dfs(x,y,mp[x][y],i);
            else  ans[i]=ans[ vis[x][y] ];
            cout<<ans[i]<<endl;
        }
    }
    View Code

    并查集:400ms

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);i--)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define pb push_back
    #define fi first
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    ///////////////////////////////////
    #define inf 0x3f3f3f3f
    
    #define N 1000+5
    int f[1001000+5];
    int sum[1001000+5];int n;
    char mp[N][N];int flag;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int find1(int x)
    {
        return f[x]==x?x:f[x]=find1(f[x]);
    
    }
    void union1(int a,int b)
    {
        int x=find1(a);
        int y=find1(b);
        if(x!=y)
        {
            sum[x]+=sum[y];
            f[y]=x;
        }
    }
    
    int dfs(int x,int y)
    {
        int id=x*n+y;
        if(f[id]!=-1)return find1(id);
        f[id]=id;sum[id]=1;
        rep(i,0,3)
        {
            int a=x+dx[i];
            int b=y+dy[i];
            if( !(a>=1&&a<=n&&b>=1&&b<=n)  )continue;
            if(mp[a][b]==mp[x][y])continue;
            int id2=a*n+b;
            union1(id,dfs(a,b));
        }
       return find1(id);
    }
    
    
    int main()
    {
        int m;
        RII(n,m);
        rep(i,1,n)
        RS(mp[i]+1);
        CLR(f,-1);
        while(m--)
        {
            int x,y;
            RII(x,y);
            printf("%d
    ",sum[ dfs(x,y) ]);
    
        }
    }
    View Code

    并查集2:300ms

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);i--)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define pb push_back
    #define fi first
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    ///////////////////////////////////
    #define inf 0x3f3f3f3f
    #define N 1000
    int f[10001000+5];
    int find1(int x)
    {
        return x==f[x]?x:f[x]=find1(f[x]);
    }
    void union1(int a,int b)
    {
        int x=find1(a);
        int y=find1(b);
        if(x!=y)f[x]=y;
    }
    
    int n,m;
    char mp[N][N];
    int num[10001000+5];
    int main()
    {
        RII(n,m);
        rep(i,1,n)
        {
            RS(mp[i]+1);
            rep(j,1,n)
            {
                int id=i*n+j;
                f[id]=id;
                if(i-1>=1)
                    if(mp[i-1][j]!=mp[i][j])
                    union1(id,(i-1)*n+j);
                if(j-1>=1)
                    if(mp[i][j-1]!=mp[i][j])
                    union1(id,i*n+j-1);
            }
        }
        
        rep(i,1,n)
        rep(j,1,n)
        {
            int id=i*n+j;
            num[ find1(id) ]++;
        }
        while(m--)
        {
            int a,b;
            RII(a,b);
            int id=a*n+b;
            printf("%d
    ",num[ find1(id) ]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    git常用命令
    Laravel框架数据库CURD操作、连贯操作总结
    Laravel 5 系列入门教程(四)【最适合中国人的 Laravel 教程】【完结】
    Laravel 5 系列入门教程(三)【最适合中国人的 Laravel 教程】
    Laravel 5 系列入门教程(二)【最适合中国人的 Laravel 教程】
    Laravel 5 系列入门教程(一)【最适合中国人的 Laravel 教程】
    linux环境下安装nginx步骤
    关于C++中的虚拟继承的一些总结
    C++中拷贝构造函数
    C++之类与对象(3)
  • 原文地址:https://www.cnblogs.com/bxd123/p/10530170.html
Copyright © 2011-2022 走看看