01迷宫-做题报告

01迷宫

2018-10-19

看到这道题就无脑bfs了,然后拿了50分。然而并不知道怎么优化。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int mmp[5000][5000];
int x,y;
int vis[5000][5000];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int ans=0;
struct node{
    int x,y;
};
queue<node> Q;
inline int bfs(int x,int y){
    node s;
    s.x=x,s.y=y;
    Q.push(s);
    vis[x][y]=1;
    ans++;
    while(!Q.empty()){
        node k=Q.front();
        Q.pop();
        for(int i=0;i<4;i++){
            node zzq;
            int sx=k.x+dx[i],sy=k.y+dy[i];
            //printf("sx=%d sy=%d\n",sx,sy);
            if(sx<=n&&sx>=1&&sy<=n&&sy>=1&&!vis[sx][sy]&&mmp[sx][sy]!=mmp[k.x][k.y]){
                //printf("SSR::sx=%d sy=%d\n",sx,sy);
                vis[sx][sy]=1;
                ans++;
                zzq.x=sx,zzq.y=sy;
                Q.push(zzq);
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            char c;
            cin>>c;
            mmp[i][j]=c-'0';
        }
    }
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        ans=0;
        bfs(x,y);
        memset(vis,0,sizeof vis);
        cout<<ans<<endl;
    }
    return 0;
}

我觉得超时主要的原因是每次输入都要询问废话,还有每次都要用memset来清空vis数组(但是不知道要怎么改啊啊啊)

然后我看了很多篇题解,终于发现了一篇适合我的:

大概的思路是记忆化

  1. 设num为第num的次输入。则anser[num]就是第num次输入的答案

  2. 把原来用来标记的vis数组的赋值步骤vis[sx][sy]=1改成vis[sx][sy]=num;因为只要在bfs(x,y)中搜索到了sx,sy;那么根据题目的性质bfs(sx,sy)和bfs(x,y)的答案是一样的;记得在开头vis[x][y]=num

  3. 最后在每一次bfs的结尾把答案存入anser[num]中,下一次搜索时如果vis[x][y]有值那么直接输出anser[vis[x][y]]即可。

    附上我的AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int mmp[5000][5000];
    int x,y;
    int vis[5000][5000];
    int anser[5000000];
    int dx[]={1,0,-1,0};
    int dy[]={0,1,0,-1};
    int ans=0;
    struct node{
    int x,y;
    };
    queue<node> Q;
    int num=0;
    inline void bfs(int x,int y){
    ans=0;
    node s;
    num++;
    if(vis[x][y]){
        cout<<anser[vis[x][y]]<<endl;
        return ;
    }
    s.x=x,s.y=y;
    Q.push(s);
    vis[x][y]=num;
    ans++;
    while(!Q.empty()){
        node k=Q.front();
        Q.pop();
        for(int i=0;i<4;i++){
            node zzq;
            int sx=k.x+dx[i],sy=k.y+dy[i];
            //printf("sx=%d sy=%d\n",sx,sy);
            if(sx<=n&&sx>=1&&sy<=n&&sy>=1&&!vis[sx][sy]&&mmp[sx][sy]!=mmp[k.x][k.y]){
                //printf("SSR::sx=%d sy=%d\n",sx,sy);
                ans++;
                vis[sx][sy]=num;
                zzq.x=sx,zzq.y=sy;
                Q.push(zzq);
            }
        }
    }
    anser[num]=ans;
    cout<<ans<<endl;
    return ;
    }
    int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            char c;
            cin>>c;
            mmp[i][j]=c-'0';
        }
    }
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        bfs(x,y);
    }
    return 0;
    }

现在是2018/12/06 我又重做了一遍这道题。

这次完全是自己的思想

我看了下样例发现了一个规律,你每次搜索时搜索到的每一个点的答案都是一样的,于是我每次dfs完直接把搜到的点的答案都更新一边就可以了。

$code$

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>

using std::vector;
using std::pair;
using std::cin;

inline void read(int &x)
{
    x=0;char ch=0;bool sign=false;
    while(ch < '0' || ch > '9')
    {
        sign|=(ch == '-');
        ch=getchar();
    }
    while(!(ch < '0' || ch > '9'))
    {
        x=x*10+(ch^48);
        ch=getchar();
    }
    x=sign ? -x : x;
}

const int dx[4]={0,0,-1,1},
          dy[4]={1,-1,0,0};
int n,m;
int x,y;
int dis[1220][1102];
char map[1300][1200];
int vis[1232][2323];
int p,k;
vector< pair<int , int> > ans;
inline void dfs(int x,int y)
{
    //printf("map[%d][%d]=%d \n",x,y,map[x][y]);
    if(dis[x][y] > 1){
        return ;
    }
    for(int i=0; i<4; i++)
    {
        int sx=x+dx[i],sy=y+dy[i];
        //printf("map[%d][%d]=%d \n",sx,sy,map[sx][sy]);
        if(sx<1 || sx>n || sy<1 || sy>n || vis[sx][sy] || map[sx][sy] == map[x][y])continue;
        vis[sx][sy]=1;
        ans.push_back({sx,sy});
        dfs(sx,sy);
        dis[x][y]+=dis[sx][sy];
    }
}

int main()
{
    read(n);read(m);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            dis[i][j]=1;
            cin>>map[i][j];
        }
        //getchar();
    }
    for(int i=1; i<=m; i++)
    {
        //memset(vis, 0 ,sizeof vis);
        read(x),read(y);
        /*if(dis[x][y] > 1)
        {
            printf("%d\n",dis[x][y]);
        }
        else
        {*/
            ans.clear();
            vis[x][y]=1;
            p=x,k=y;
            dfs(x,y);
            for(int i=0; i<ans.size(); i++)
            {
                //printf("x=%d y=%d ans[%d][%d]=%d\n",x,y,ans[i].first,ans[i].second,dis[x][y]);
                dis[ans[i].first][ans[i].second]=std::max(dis[x][y],dis[ans[i].first][ans[i].second]);
            }
            printf("%d\n",dis[x][y]);
        //}
    }
    return 0;
}

之前忘了每次询问都要ans.clear();了,然后还一度怀疑自己的做法是错的。。。

posted @ 2018-10-19 10:03  加固文明幻景  阅读(4)  评论(0编辑  收藏  举报  来源