zoukankan      html  css  js  c++  java
  • 麦当劳叔叔的难题

    麦当劳叔叔的难题

    https://www.luogu.com.cn/problem/P1713

    前言:

    题目本身并不难(虽然是绿题),只要敲代码的时候细心就好

    However,蒟蒻表示有一个玄学的问题想请教大家QAQ(请大家移步最后或慢慢看到最后)


    题目简述:

    给你n×n的地图,以及m个障碍的坐标,起点是(n,1),终点是(1,n)

    要求求出从起点到终点所用时间的最大时间差,即:求最短路径和最长路径的差


    思路&代码Code:

    题意还是很清晰明了的,用搜索(记忆化!)可以解决

    • 方法一:BFS+DFS,先求最短路径,再求最长路径

    BFS部分就是裸的板子(我是手写队列党quq)

    DFS部分在不加记忆化之前也是裸的板子

    注意:在记忆化之前,建议先DFS再BFS,这样bool数组就可以只开一个;但是记忆化之后,因为在DFS中需要用到BFS中求到的最小值,所以是先BFS再DFS,那么记录是否走过的bool数组就需要开两个

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,x,y,last,first;
    int f[1001][1001],dis[1001][1001];
    bool pd[1001][1001],flag[1001][1001];
    int dx[4]={1,0,0,-1};  //搜索顺序真的很坑啊!!在最后会提出 
    int dy[4]={0,1,-1,0}; 
    
    struct node { //手写队列 
    	int x,y,st;
    } q[100010];
    
    inline void bfs(int xx,int yy) { //bfs求最小值 
    	int front=1,tail=1;
    	q[front].x=xx;
    	q[front].y=yy;
    	q[front].st=0;
    	while(front<=tail) {
    		for(register int i=0;i<4;i++) {
    			int xs=q[front].x+dx[i];
    			int ys=q[front].y+dy[i];
    			if(xs>=1&&xs<=n&&ys>=1&&ys<=n&&pd[xs][ys]==false) {
    				pd[xs][ys]=true;
    				tail++;
    				q[tail].x=xs;
    				q[tail].y=ys;
    				q[tail].st=q[front].st+1;
    				if(xs==1&&ys==n) { //到达终点,将最小值记录在first中 
    					first=q[tail].st;
    					return ;
    				}
    			}
    		}
    		front++;
    	}
    }
     
    inline void dfs(int xx,int yy) { //dfs求最大值 
    	if(dis[xx][yy]>first&&dis[xx][yy]<f[xx][yy]) return ; //剪枝优化,否则会T第8个点 
    	if(xx==1&&yy==n) {
    		if(last<dis[xx][yy]) { //更新最大值 
    			last=dis[xx][yy];
    			for(register int i=1;i<=n;i++) { //记忆化 
    				for(register int j=1;j<=n;j++) {
    					f[i][j]=dis[i][j];
    				}
    			}
    		}
    		return ;
    	}
    	for(register int i=0;i<4;i++) {
    		int xs=xx+dx[i];
    		int ys=yy+dy[i];
    		if(xs>=1&&xs<=n&&ys>=1&&ys<=n&&flag[xs][ys]==false) { //注意因为先bfs,所以要开两个bool数组记录路径 
    			dis[xs][ys]=dis[xx][yy]+1;
    			flag[xs][ys]=true;
    			dfs(xs,ys);
    			flag[xs][ys]=false;
    			dis[xs][ys]=0;
    		}
    	}
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(register int i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y); 
    		pd[x][y]=flag[x][y]=true; //障碍物直接标记为走过即可,但是不计入步骤数 
    	}
    	pd[n][1]=flag[n][1]=true; //注意起点要标记为走过 
    	bfs(n,1);
    	//printf("%d",first);
    	dfs(n,1);
    	//printf("%d ",last);
    	printf("%d",last-first);
    	return 0;
    }
    
    
    • 方法二:当然了,DFS也是可以同时求最短和最长的

    一个DFS也是需要记忆化的,不能也会T掉(这坑代码的第8个点),具体的见代码吧

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,x,y,a[12][12],flag[15][15],first=0x7ffffff,last=-1;
    int f[15][15],d[15][15],u[15][15]; //f数组记录当前步数,d数组记录最小步数,u数组记录最大步数
    inline int dfs(int now,int x,int y) {
    	if(x>n||y>n||x<1||y<1||flag[x][y]==1)return 0;
    	if(now>first&&now<u[x][y])return 0; 
    	/*剪枝,如果当前到达这个点后,步数超过了当前答案最小值或步数小于当前格子的最大步数u[x][y],return*/
    	f[x][y]=now;
    	if(x==1&&y==n) { //更新答案 
    		if(first>now) {
    			for(register int i=1;i<=n;i++) {
    				for(register int j=1;j<=n;j++) {
    					d[i][j]=f[i][j];
    				}
    			}
    			first=now;
    		}
    		if(last<now) {
    			for(register int i=1;i<=n;i++) {
    				for(register int j=1;j<=n;j++) {
    					u[i][j]=f[i][j];
    				}
    			}
    			last=now;
    		}
    		return 0;
    	}
    	flag[x][y]=1;
    	dfs(now+1,x+1,y); //四个方向 
    	dfs(now+1,x-1,y);
    	dfs(now+1,x,y+1);
    	dfs(now+1,x,y-1);
    	flag[x][y]=0;
    	f[x][y]=0;
    	return 0;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for(register int i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y);
    		flag[x][y]=1;
    	}
    	for(register int i=1;i<=n;i++) {
    		for(register int j=1;j<=n;j++) {
    			u[i][j]=-1;
    			d[i][j]=0x7ffffff;
    		}
    	}	
    	dfs(1,n,1);
    	printf("%d",last-first);
    	return 0;
    }
    
    
    • 方法三:貌似网络流?大家可以自己研究一下(研究不出来别打我,我看洛谷讨论有说网络流的

    好了,接下来才是本题的重点

    问题请教:

    在这道题中,如果搜索顺序不同,那么结果也会不同,就会导致得分不同(这..这..)

    具体差别:

    如下,会T掉第8个点
    int dx[4]={1,0,-1,0};  
    int dy[4]={0,1,0,-1};
    
    如下,也会T掉第8个点
    int dx[4]={0,1,0,-1};
    int dy[4]={1,0,-1,0};
    
    如下,会Wa掉第6个点
    int dx[4]={0,1,0,-1};
    int dy[4]={1,0,-1,0};
    
    但是如下,就AC了
    int dx[4]={1,0,0,-1};  
    int dy[4]={0,1,-1,0};
    

    你说顺序不一样T了可以理解,顶多数据问题嘛,毕竟在搜索中有优化搜索顺序这个剪枝

    但是Wa我真的就不能理解了,要说代码问题,那其他的怎么就是TLE呢...

    而且,有时在其他题目中也会遇到这种情况

    来自蒟蒻的求助QAQ

    PS:当然了,有时是数据非故意卡,但有时是出题人专门卡你(这就很无奈)


  • 相关阅读:
    C51 使用端口 个人笔记
    C51 静态数码管 个人笔记
    C51 矩阵按键 个人笔记
    C51 蜂鸣器 个人笔记
    C51 独立按键 个人笔记
    C51 中断 个人笔记
    CC3200 TI 笔记
    iar修改包含路径的方法
    WCF绑定和行为在普通应用和SilverLight应用一些对比
    用批处理来自动化项目编译及部署(附Demo)
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13137545.html
Copyright © 2011-2022 走看看