zoukankan      html  css  js  c++  java
  • 5月18日考试错误题目走迷宫

    BFS走迷宫

    一场考试引发的探究

    题面

    一个n行m列的迷宫, 0能走, 1不能走, 八连通.

    输出从1,1走到n,m的路径.

    样例:

    输入

    1 2
    0 0
    

    输出

    1 1
    1 2
    

    注: 未说明八联通优先级, 所以优先级全靠蒙

    附原题题目:

    https://files.cnblogs.com/files/Wild-Donkey/T2迷宫问题(labyrinth).bmp

    探索

    一开始用的是DFS, 但是没有过, 得了52分. 理论上说的确过不了.

    首先怀疑的是优先级问题, 当将52分程序的优先级改成标程的优先级时, 还是52分.

    在题解过程中, 得分最多的同学竟然用的是四联通, 58分. 这时, 将另外一个和我同分的同学的程序改成了四联通, 果然得了58分.

    分析数据时, 发现这个数据输出的是最短路径, BFS.

    后来又打了个BFS, 确认无误后跑了几个点.

    52分BFS
    #include <iostream>
    using namespace std;
    int l,r,n,m,fx[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}},q[10005][2],cnt=0,ans[10005][2],fa[1005][1005];
    bool a[1005][1005],flg=0;
    void BFS(){
    	int bx,by;
    	while(l<r){
    		int nx,ny;
    		bx=q[l][0];
    		by=q[l][1];
    		a[bx][by]=1;
    		l++;
    		if((bx==n)&&(by==m)){
    			flg=1;
    			return;
    		}
    		for(int i=0;i<8;i++){
    			nx=bx+fx[i][0];
    			ny=by+fx[i][1];
    			if((nx>0)&&(nx<=n)&&(ny>0)&&(ny<=m)){
    				if(!a[nx][ny]){
    					a[nx][ny]=1;
    					q[r][0]=nx;
    					q[r++][1]=ny;
    					fa[nx][ny]=i;
    				}
    			}
    		}
    	}
    	return;
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			cin>>a[i][j];
    		}
    	}
    	l=1;
    	r=2;
    	q[l][0]=1;
    	q[l][1]=1;
    	BFS();
    	if(flg==0){
    		cout<<-1<<endl;
    		return 0;
    	}
    	int nx,ny,tx,ty;
    	nx=n;
    	ny=m;
    	while((nx>0)&&(nx<=n)&&(ny>0)&&(ny<=m)){
    		ans[++cnt][0]=nx;
    		ans[cnt][1]=ny;
    		tx=nx;
    		ty=ny;
    		nx-=fx[fa[tx][ty]][0];
    		ny-=fx[fa[tx][ty]][1];
    	} 
    	for(int i=cnt;i>=1;i--){
    		cout<<ans[i][0]<<" "<<ans[i][1]<<endl;
    	}
    	return 0;
    } 

    手动模拟出错的数据, 发现标准输出不成立.

    造一个简单的数组做例子:

    输入

    2 3
    0 0 1
    1 0 0
    

    按说应该输出

    1 1
    2 2
    2 3
    

    但是标程输出为

    -1
    

    随后仔细检查标程

    标程
    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    #include <queue>
    using namespace std<
    #define MAX 105
    int tx[9]={0,0,1,1,1,0,-1,-1,-1};
    int ty[9]={0,1,1,0,-1,-1,-1,0,1};
    int map[MAX][MAX];
    struct node
    {
        int x,y;
    }pre[MAX][MAX];
    int m,n; 
    void init()
    {
      int i,j;
      scanf("%d",&n);
      scanf("%d",&m);
      for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
          scanf("%d",&map[j][i]);//问题所在
      for(i=0;i<=n;i++)
        map[i][0]=map[i][m+1]=1;
      for(i=0;i<=m;i++)
        map[0][i]=map[n+1][i]=1;
    }
    void print(int x,int y)
    {
      if(x==1 && y==1)
      {
        printf("1 1
    ");
        return ;
      }
      print(pre[x][y].x,pre[x][y].y);
      printf("%d %d
    ",x,y);
    }
    void bfs()
    {
      int i,j,k;
      queue<node> q;
      node first;
      first.x=1;
      first.y=1;
      q.push(first);
      while(!q.empty())
      {
        first=q.front();
        q.pop();
        for(i=1;i<=8;i++)
        {
          int dx=first.x+tx[i];
          int dy=first.y+ty[i];
          if( map[dx][dy]==0 )
          {
            node now;
            now.x=dx;
            now.y=dy;
            q.push(now);
            pre[dx][dy].x=first.x;
            pre[dx][dy].y=first.y;
            map[dx][dy]=-1;
            if(dx==n && dy==m)
            {
              print(dx,dy);
              return;
            }
          }
        }
      }
      printf("-1
    ");
    }
    int main()
    {
      init();
      bfs();
      return 0;
    }

    在标程中, 输入是这样打的:

    for(i=1;i&lt;=m;i++)//列
    	for(j=1;j&lt;=n;j++)//行
    		scanf("%d",&map[j][i]);
    

    这就使得矩阵存成这样:

    0 1 0 
    0 1 0
    

    所以输出的是-1

    这就是为什么四联通会比八连通分高, 它比八连通多判断了一个点的-1.

    为了验证猜想, 我把我打的52分BFS的输入改成这样:

    for(int i=1;i<=m;i++){
    	for(int j=1;j<=n;j++){
    		cin>>a[j][i];
    	}
    }
    

    然后就过了.

    所以标程的问题就出在这输入上.

    修改后满分但是实际上是错误的BFS
    #include
    using namespace std;
    int l,r,n,m,fx[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}},q[10005][2],cnt=0,ans[10005][2],fa[1005][1005];
    bool a[1005][1005],flg=0;
    void BFS(){
    	int bx,by;
    	while(l<r){
    		int nx,ny;
    		bx=q[l][0];
    		by=q[l][1];
    		a[bx][by]=1;
    		l++;
    		if((bx==n)&&(by==m)){
    			flg=1;
    			return;
    		}
    		for(int i=0;i<8;i++){
    			nx=bx+fx[i][0];
    			ny=by+fx[i][1];
    			if((nx>0)&&(nx<=n)&&(ny>0)&&(ny<=m)){
    				if(!a[nx][ny]){
    					a[nx][ny]=1;
    					q[r][0]=nx;
    					q[r++][1]=ny;
    					fa[nx][ny]=i;
    				}
    			}
    		}
    	}
    	return;
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=m;i++){
    		for(int j=1;j<=n;j++){
    			cin>>a[j][i];
    		}
    	}
    	l=1;
    	r=2;
    	q[l][0]=1;
    	q[l][1]=1;
    	BFS();
    	if(flg==0){
    		cout<<-1<<endl;
    		return 0;
    	}
    	int nx,ny,tx,ty;
    	nx=n;
    	ny=m;
    	while((nx>0)&&(nx<=n)&&(ny>0)&&(ny<=m)){
    		ans[++cnt][0]=nx;
    		ans[cnt][1]=ny;
    		tx=nx;
    		ty=ny;
    		nx-=fx[fa[tx][ty]][0];
    		ny-=fx[fa[tx][ty]][1];
    	} 
    	for(int i=cnt;i>=1;i--){
    		cout<<ans[i][0]<<" "<<ans[i][1]<<endl;
    	}
    	return 0;
    }
    

    所以说这道题的正确标程应该是52分的BFS.

  • 相关阅读:
    UIFont的使用和字体类型总结
    LOJ-10100(割点个数)
    LOJ-10099(点双联通)
    poj-3177(并查集+双联通分量+Tarjan算法)
    图论:割点和桥
    牛客训练五:炫酷数学(思维)
    牛客训练五:炫酷路途(c++与dp)
    并查集的两种实现(按秩合并+路径压缩)
    牛客训练六:海啸(二维树状数组+vector函数的使用)
    牛客训练六:美食(贪心)
  • 原文地址:https://www.cnblogs.com/Wild-Donkey/p/12940977.html
Copyright © 2011-2022 走看看