BFS+DFS

Catch That Cow

题意:
John在坐标n上,可以左移右移加跳跃,牛在坐标k上且不动,至少多久抓住牛

//#include<bits/stdc++.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
#include <queue>
#include <string.h>
const int MAXX=100000;
struct node{
	int x;
	int step;//这个点的位置是x,从出发点走了step步,一步一分钟
	node(int xx,int s):x(xx),step(s){} //这种构造方法 
	node(){}//空的构造函数,才允许node p 
};
//queue<node> a[MAXX+10];和vector不同 
queue<node> a;
int vis[MAXX+10];//给下标 设置判重标记,看看这个节点是否已经被扩展过 
int main(){
	ios_base::sync_with_stdio(0);
	int n,k;//John在坐标n上,可以左移右移加跳跃,牛在坐标k上且不动,至少多久抓住牛
	cin>>n>>k;
	memset(vis,0,sizeof(vis)); 
	node p;
	p.x=n;
	p.step=0;
	a.push(p);//第一步先把初始节点放入队列 
	vis[n]=1;
	while(!a.empty()){//队列不为空就逐一出队,并将出队的节点的邻接节点入队 
		node q=a.front();
		if(q.x==k){
			cout<<q.step<<endl;
			return 0;
		} 
		else{//若出队的节点为目标节点可以he了,若队列空了也没找到目标节点就be 
			if(q.x-1>=0&&!vis[q.x-1]) {
//				q.x=q.x-1;怎么重新创建一个匿名的node对象 
//				q.step=q.step+1;
				a.push(node(q.x-1,q.step+1)) ;
				vis[q.x-1]=1;
			}
				if(q.x+1<=MAXX&&!vis[q.x+1]) {
				a.push(node(q.x+1,q.step+1)) ;
				vis[q.x+1]=1;
			}
			if(2*q.x<=MAXX&&!vis[2*q.x]) {
				a.push(node(2*q.x,q.step+1)) ;
				vis[2*q.x]=1;
			}
			a.pop();
		}
	} 
    return 0;
} 

 

6264:走出迷宫(BFS、DFS剪枝)

传送门
题意:假设你已经得到了一个n*m的迷宫的图纸,已知起点和终点坐标,请你找出从起点到出口的最短路。
BFS板子题

//#include<bits/stdc++.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
#include <queue>
#include <string.h>
int m,n;
int ex,ey;
struct node{
	int x;
	int y;
	int step;
	node(int xx,int yy,int steps):x(xx),y(yy),step(steps){};
};
char a[105][105];
int vis[105][105];
int dx[4]={-1,1,0,0};//上下左右 
int dy[4]={0,0,-1,1};
int main(){
	ios_base::sync_with_stdio(0);
	queue<node> q;
	cin>>m>>n;
	for(int i=0;i<m;i++){
		cin>>a[i];
	}
	memset(vis,0,sizeof(vis));
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			if(a[i][j]=='S'){
				q.push(node(i,j,0));
				vis[i][j]=1;
			}
			if(a[i][j]=='T'){
				ex=i; 
				ey=j;
			}
		}
	}
	while(!q.empty()){
		node p=q.front();
		if(p.x==ex&&p.y==ey){
			cout<<p.step<<endl;
			return 0;
		}
		else{
//			if(p.x+1<m&&p.y+1<n&&!vis[p.x+1][p.y+1])
		for(int i=0;i<4;i++){
	 		int cx=p.x+dx[i];
	 		int cy=p.y+dy[i];
	 		if(cx>=0&&cx<m&&cy>=0&&cy<n){
	 			if(!vis[cx][cy]&&a[cx][cy]!='#'){
	 				q.push(node(cx,cy,p.step+1));
	 				vis[cx][cy]=1;
//少了就6分 感觉像DFS中的剪枝,但 dfs不剪枝会tle可是这个会memory LImit Exceeded 
				 }
			 }
		 }
		q.pop();
	 }
}
    return 0;
} 

 

int lastminL[105][105];
时间换空间,剪枝来了,dfs要逐一走很多条路
且每条路都走到终点罢休所以超时,而且每次都只单独存储正在走的这一条路
不知道别的路情况怎么样,比如走到同一个点a[i][j],上一条路用了x步,
这条路用了y步,那这条路自然就不继续走下去了,return。但由于只
单独存储一条路,无法与别的路进行比较,因此空间换时间,用这个数组lastminL[i][j]
记录之前走的若干条路走到a[i][j]时用的最小步数,如果再走一条路走到这个点,用的
步数超过了 lastminL[i][j],那么这条路就不用走了
就像寻路问题ROADS那题(找最短路径),也开了一个数组minL[i][j]表示从1走到城市i
且经费还剩j时所走的长度,如果后续的路上恰好走到i剩j钱且走的路长于minL[i][j]就不走了
还有一个剪枝条件,(最优性剪枝和可行性剪枝,暂时对不上号)
就是也许有的路已经走完得到结果需要走minx这么长,可这条路某阶段已经超过minx就pass

对了还有一个值得注意的地方就是设置无穷大的值的时候,一会儿1<<30,一会儿0x3f3f3f
这样就会出问题噢
step 既与 lastminL[x][y](初始化为1<<30)比较
又与minx(初始化为 0x3f3f3f)比较
虽然我还没扪清到底哪一步 让minx与lastminL[x][y]间接比上了

#include <bits/stdc++.h>		
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
int m,n; 
char a[105][105];
	int ps,qs,pe,qe;
int minx=1<<30;//也可以用1<<30;这种形式表示一个很大的数 
int dx[4]={-1,1,0,0};//上下左右 
int dy[4]={0,0,-1,1};
int vis[105][105];
//int step=-1; 
int lastminL[105][105];//到上次路为止走到a[i][j]用的最少步数(比出来的) 
void dfs(int x,int y,int step){//第x行,第y列 
	 if(vis[x][y])return;
	 if(step>=minx)return;
		 if(step>=lastminL[x][y])return;
		 else lastminL[x][y]=step;//lastminL[i][j]是逐一比较更新出来的 
	 		vis[x][y]=1;
	 		if(x==pe&&y==qe){
	 			minx=min(minx,step);
//dfs是每一条路径都走遍了才确定找出最小的step 
	 			return;
			 }
	 	for(int i=0;i<4;i++){
//	 		step=kkk;//dfs没有搜到是要回溯的。。。回到原来的step,每次step--也行 
	 		int cx=x+dx[i];
	 		int cy=y+dy[i];
	 		if(cx>=0&&cx<m&&cy>=0&&cy<n){
	 			if(!vis[cx][cy]&&a[cx][cy]!='#'){
	 				dfs(cx,cy,step+1);
//				 step--; 回溯回来不仅要考虑还原step,还有vis数组 
					vis[cx][cy]=0; //加上这条,果然就tle了,这才是dfs硬解这题的反应
//		so 接下来应该剪枝!how to do 
				 }
			 }
		 }
}
int main(){
	
	cin>>m>>n;
	for(int i=0;i<m;i++){
		cin>>a[i];
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			lastminL[i][j]=(1<<30); 
		}
	} 
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			if(a[i][j]=='S'){
				ps=i; 
				qs=j;
			}
			if(a[i][j]=='T'){
				pe=i; 
				qe=j;
			}
		}
	}
	memset(vis,0,sizeof(vis));
	dfs(ps,qs,0);
	cout<<minx;
    return 0;
}

保留注释部分是为了更好地与没剪枝的样子对比
下面是没剪枝的tle代码

#include <bits/stdc++.h>		
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
int m,n; 
char a[105][105];
	int ps,qs,pe,qe;
int minx=0x3f3f3f3f;//也可以用2<<30;这种形式表示一个很大的数 
int dx[4]={-1,1,0,0};//上下左右 
int dy[4]={0,0,-1,1};
int vis[105][105];
int step=-1; 
void dfs(int x,int y){//第x行,第y列 
	 if(vis[x][y])return;
	 else{
	 		vis[x][y]=1;
	 		step++;
	 		if(x==pe&&y==qe){
	 			minx=min(minx,step);
//dfs是每一条路径都走遍了才确定找出最小的step 
	 			return;
			 }
		int kkk=step;
	 	for(int i=0;i<4;i++){
	 		step=kkk;//dfs没有搜到是要回溯的。。。回到原来的step 
	 		int cx=x+dx[i];
	 		int cy=y+dy[i];
	 		if(cx>=0&&cx<m&&cy>=0&&cy<n){
	 			if(!vis[cx][cy]&&a[cx][cy]!='#'){
	 				dfs(cx,cy);
//					 step--; 回溯回来不仅要考虑还原step,还有vis数组 
					vis[cx][cy]=0; //加上这条,果然就tle了,这才是dfs硬解这题的反应
//		so 接下来应该剪枝!how to do 
				 }
			 }
		 }
	 }
}
int main(){
	cin>>m>>n;
	for(int i=0;i<m;i++){
		cin>>a[i];
	}

	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			if(a[i][j]=='S'){
				ps=i; 
				qs=j;
			}
			if(a[i][j]=='T'){
				pe=i; 
				qe=j;
			}
		}
	}
	memset(vis,0,sizeof(vis));
	dfs(ps,qs);
	cout<<minx;
    return 0;
}

1159:Maze(BFS不止一次,没有限制的BFS一次可以遍历所有节点,一旦对某些节点加以限制,那么限制的节点可以到达却不入队,它的拓展节点自然不能通过它被访问到更别提入队,一次BFS之后再判断限制的节点能否入队,入队之后,以该限制节点为起始节点BFS

题意:A—E五道门,迷宫中有几把对应的钥匙a—e(A对应a)就需要集齐所有的钥匙才能开对应的这道门,问从起始点能否到达终点(终点可能被门或墙围拦住,导致BFS永远遍历不到

#include<iostream>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=40;
struct Node{
    int x,y;
    Node() {}
    Node(int xx,int yy){
        this->x=xx;
        this->y=yy;
    }
 
};
//钥匙/门的哈希值相同 通过门的哈希值找到对应的钥匙  A a
struct Door{
    int num;   //总共数量
    int sum;  //遇到的数量
}door[maxn];
 
queue<Node> Q;
char G[maxn][maxn];
int n,m;
int vis[maxn][maxn],vis_door[maxn];
const int go[][2]={1,0,
                   -1,0,
                   0,1,
                   0,-1};
void init(){
    while(!Q.empty()) Q.pop();
    memset(vis,0,sizeof(vis));
    memset(vis_door,0, sizeof(vis_door));
    for(int i=0;i<maxn;i++){
        door[i].num=0;
        door[i].sum=0;
    }
}
 
void read(){
    //从1开始读入
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>G[i][j];
            if(G[i][j]>='a' && G[i][j]<='e'){
                door[G[i][j]-'a'].num++;   //hash
            }
            else if(G[i][j]=='S'){
                vis[i][j]=1;
                Q.push(Node(i,j));
            }
        }
 
    }
 
}
 
bool inside(int x,int y){
    return x>=1 && x<=n && y>=1 && y<=m ;
}
void BFS(){
    bool f=true;
    while(f){
        //bfs + 标记门和钥匙
        while(!Q.empty()){
            //如果出口
            Node cur=Q.front(); Q.pop();
            int x=cur.x,y=cur.y;
            if(G[x][y]=='G'){
                cout<<"YES"<<endl;
                return;
            }//终点这个节点能否入队 
 
            for(int i=0;i<4;i++){//对队列中的节点进行扩展 
                int xx=x+go[i][0];
                int yy=y+go[i][1];
                if(inside(xx,yy) && G[xx][yy]!='X' ){
                    char c=G[xx][yy];
                    if(vis[xx][yy]) continue;
                    //钥匙
                    else if(c>='a' && c<='e'){
                        door[c-'a'].sum++;
                    }
                    else if(c>='A' && c<='E'){
                        vis_door[c-'A']=1;
                        continue; //注意这个位置  队列里加入的到底是啥
                    }
                    vis[xx][yy]=1;
                    Q.push(Node(xx,yy));//除了墙和门不能入队,哪怕是终点也可以直接入队,如果在碰见门之前碰见了终点,直接入队,BFS说明 终点比门离起点更近 
                }
            }//出队并对出对元素进行拓展(看情况让拓展的元素入队) 
 
        }//完成了一轮BFS,队列已经为空了,终点没进过队,要么是被墙挡住了要么是被门挡住了 
        f=false;
        //检查门能不能开 vis_door
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(G[i][j]>='A' && G[i][j]<='E' && !vis[i][j] ){
                    char c=G[i][j];
                    int id=c-'A';
                    if(vis_door[id] && door[id].num>0 && door[id].num==door[id].sum){
                        vis[i][j]=1;
                        Q.push(Node(i,j));//是被门挡住了且钥匙已经集齐,将门入队,那么再一轮BFS(从队列队首元素开始,如果终点是被门挡住的,终点就会作为该门的拓展节点入队 
                        f= true;
                    }
                }
            }
 
        }
 
    }
    cout<<"NO"<<endl;//要么是被墙挡住的,要么是被门挡住的但是没集齐钥匙
//	?万一钥匙离起点更远,到了门还没到钥匙呢?(那么钥匙就永远到不了的) 
//不存在的,只要钥匙四周有能被扩展的点那么一次BFS就一定能将钥匙入队,
//除非钥匙被墙、门包围了,那这种情况下的没集齐钥匙(没集齐钥匙只会是这种情况 )
//就永远不可能集得齐 

 
//BFS的特点,BFS扩展完一轮其实是可以将所有的节点都走一遍的,只是有些节点不允许
//入队,那么它的扩展节点 嘿,也不一定不能入队,如果它的扩展节点也是别的能扩展的扩展节点
//如果一个节点不能被到达(到达了却不允许入队的也算是到达了),那一定是它周围的节点
//都能被到达,却都不能入队,导致该节点不能被扩展入队 
//我感觉我又可以了 
//之前做的题其实都是在一遍BFS过程中完成的,一次BFS所有的点都可以到达并入队
}
 
int main(){
    while(cin>>n>>m && (n&&m)){
        init();
        read();
        BFS();
    }
    return 0;
}

自己再来一遍

 #include<bits/stdc++.h>
using namespace std;
int m,n;
char a[25][25];
int dx[4]={1,-1,-0,0};
int dy[4]={0,0,1,-1};
struct node{
	int x;
	int y;
	node(int xx,int yy):x(xx),y(yy){};
};
struct door{
	int num;//对于这扇门共有多少把钥匙 
	int sum; //对于这扇门集齐了多少把钥匙 
}door[5];
queue<node> q;
int vis_door[5];//终点不能入队,记录是不是门挡住的 
int vis[25][25];
void bfs(){
	int flag=true;
	while(flag){
			while(!q.empty()){//开始来一次bfs全扫一遍 
		node p=q.front(); q.pop();//放在循环体中的最后一条也行 
		 if(a[p.x][p.y]=='G'){
		 	cout<<"YES"<<endl;
		 	return ;//顺利找到终点,没有受到门和墙的阻拦 
		 } 
		 else{
		 	for(int i=0;i<4;i++){
					int cx=p.x+dx[i];
					int cy=p.y+dy[i];
					if(cx>=0&&cx<m&&cy>=0&&cy<n&&!vis[cx][cy]){
						if(a[cx][cy]=='X')continue;//到达过但不入队,不能通过它到达它的扩展节点
						else if(a[cx][cy]>='a'&&a[cx][cy]<='e'){
							door[a[cx][cy]-'a'].sum++;
							//记录找到的钥匙,这个节点是要入队的,不能用 continue; 
						} 
						else if(a[cx][cy]>='A'&&a[cx][cy]<='E') {
							vis_door[a[cx][cy]-'A']=1;
							continue;//门是不能直接入队的 
						}
						vis[cx][cy]=1;
						q.push(node(cx,cy));
					}
			 }
		 } 
	}//一次bfs结束了,如果到达了终点会return,否则还要看看终点没入队是不是被门
//挡住了,如果门能开那还有到达终点的希望,将门入队(即以门为起始节点再进行BFS扩展 
 	flag=false;
	 for(int i=0;i<m;i++){//来看看有没有找齐钥匙的门 
	 	for(int j=0;j<n;j++){
	 		if(a[i][j]>='A'&&a[i][j]<='E'&&!vis[i][j]){
	 			if(vis_door[a[i][j]-'A']&&door[a[i][j]-'A'].num==door[a[i][j]-'A'].sum){
	 				flag=true;
	 				vis[i][j]=1;
	 				q.push(node(i,j));
				 }
			 }
		 } 
	 } //如果没有一扇门能打开看看能否拓展到终点,就be了 
//	  if(!flag)cout<<"NO"<<endl; flag不能重新被赋值true自然不能再BFS就输出no啦 
	}
		cout<<"NO"<<endl; 
}
int main(){
	ios_base::sync_with_stdio(0);
	while(cin>>m>>n){
		if(m==0&&n==0)return 0;
		
		while(!q.empty())q.pop();
		memset(vis,0,sizeof(vis));
		memset(vis_door,0,sizeof(vis_door));
		for(int i=0;i<5;i++){
			door[i].num=0;
			door[i].sum=0;
		}//因为有多组数据,一定要完完整整地全盘初始化 
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				cin>>a[i][j];
				if(a[i][j]=='S'){
//					sx=i; sy=j;
				q.push(node(i,j));//将起始节点入队了 
				vis[i][j]=1; 
				}
				if(a[i][j]>='a'&&a[i][j]<='e'){//累计有多少把钥匙 
					door[a[i][j]-'a'].num++; 
				}
			}
		} 
		bfs(); 
	}
    return 0;
} 

TLE,问题在于vis数组的置1 和 push入队 是否被忘记
第一次BFS,但凡不是墙,不是门,且!vis[i][j]没被拓展进队过,就应该push进队且勿忘vis【i】【j】置1
第一次BFS没能到达目标点,之后要看目标点没能入队的原因是被墙拦住了(没救了)还是被门拦住了(有希望,如果到达过该门且现在该门对应的钥匙集齐了,就应该将该门入队展开BFS,同时由于该门入队了,vis【i】【j】要置为1,判断是否入队时忘记了**!vis【i】【j】**这个条件
第一次BFS到达了门却不管钥匙情况,一概不让门入队,应为要等BFS走完所有能走的地方收集完所有能收集的钥匙之后才能确保一扇门是否能被打开。
由于没有保留所有门的坐标,还需要从a迷宫数组中去找门,会找到所有的门并把全部能开的门都入队,届时就可以通过这些点为中心BFS,万一通过 第一次找到能入队的门 还是不能到达终点,但是可能集齐了另外的钥匙能进入上次开不了的门,所以要再遍历a迷宫数组去找能开的门,这时就要避免被上次开过的门蒙蔽了,上回开过且没找到,又通过这扇门去BFS,时间就耗在这儿了,所以开过的门(入过队的门也要标记vis【i】【j】为1,下次得有别的新的门能够打开才有希望寻到新的地方(也许存在目标点)
逻辑有点多,遵循规则就好,凡是入队过(BFS拓展过的节点,vis【i】【j】统统置为1,找能否入队的点也一定要判断 !vis【i】【j】,避免重复入队,这个节点能BFS到的范围已经考虑过了,再寻无意义,不会有新发现。

6044:鸣人和佐助

6044:鸣人和佐助

一开始一个不小心被提示:
每个节点ckl的状态可能会发生改变,对于判重数组,原来的vis数组----->开一个三维数组来存放所有状态的标志位
这题相比于走迷宫的题,多了一个查克拉ckl的数目。从初始状态到目标状态至少要多少步?走迷宫那道题的状态就是位置的坐标,这题的状态可视作三维的,如果在同一个点拥有着不同的查克拉数量也视作不同的状态,后续到达的点走过的路会不一样。
接着按照BFS套路一通做也AC了,可见套路不变。
但是判重的过程中有些想不通,有的节点是多次入队拓展的,与传统bfs的判重规则不一样,也没想到有什么情况需要重新扩展一次某节点。

 #include<bits/stdc++.h>
using namespace std;
int r,c,k;
char a[202][202];
int vis[202][202][15];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
struct node{
	int x;
	int y;
	int step;
	int ckl;
	node(int i,int j,int k,int tt):x(i),y(j),ckl(k),step(tt){};
};
queue<node> Q;
void bfs(){
	while(!Q.empty()){
		node p=Q.front();Q.pop();
		int xx=p.x;
		int yy=p.y;
		if(a[xx][yy]=='+'&&p.ckl>=0){
			cout<<p.step<<endl;
			return ;
		}
		 else{
//		 	if(p.ckl<=0){
//		 		cout<<"-1"<<endl;
//		 		return ;草率了,说不定周边没有#呢,还是得bfs结束,队列为空仍然没找到+ 
//			 }
		 	for(int i=0;i<4;i++){
		 		int x=xx+dx[i];
		 		int y=yy+dy[i];
		 		if(x>=0&&x<r&&y>=0&&y<c){
		 			
		 			if(a[x][y]=='#'){
		 				if(p.ckl<=0)continue;
		 				if(vis[x][y][p.ckl-1])continue;
		 				else{
		 					Q.push(node(x,y,p.ckl-1,p.step+1));
		 					vis[x][y][p.ckl-1]=1;
						 }
					}
		 			else {
		 				if(vis[x][y][p.ckl])continue;
		 				else{
		 					Q.push(node(x,y,p.ckl,p.step+1));
		 					vis[x][y][p.ckl]=1;
						 }

					 }
				 }
			 }
		 }
	}
		 cout<<"-1"<<endl;
}
int main(){//r,c,k数据范围很大设置标志数组可能会超内存 
	ios_base::sync_with_stdio(0);

	cin>>r>>c>>k;
	memset(vis,0,sizeof(vis));
	 for(int i=0;i<r;i++){
	 	for(int j=0;j<c;j++){
	 		cin>>a[i][j];
	 		if(a[i][j]=='@'){
	 			Q.push(node(i,j,k,0));
	 			vis[i][j][k]=1;
			 }
		 }
	 }
	 bfs();

    return 0;
} 

于是又按老套路做了一遍,以5分wa了

 #include<bits/stdc++.h>
using namespace std;
int r,c,k;
char a[202][202];
int vis[202][202];
int ckl[202][202]; 
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
struct node{
	int x;
	int y;
	int step;
//	int ckl;
	node(int i,int j,int tt):x(i),y(j),step(tt){};
};
queue<node> Q;
void bfs(){
	while(!Q.empty()){
		node p=Q.front();Q.pop();
		int xx=p.x;
		int yy=p.y;
		if(a[xx][yy]=='+'&&ckl[xx][yy]>=0){//&&ckl[xx][yy]>=0
			cout<<p.step<<endl;
			return ;
		}
		 else{
//		 	if(p.ckl<=0){
//		 		cout<<"-1"<<endl;
//		 		return ;草率了,说不定周边没有#呢,还是得bfs结束,队列为空仍然没找到+ 
//			 }
		 	for(int i=0;i<4;i++){
		 		int x=xx+dx[i];
		 		int y=yy+dy[i];
		 		if(x>=0&&x<r&&y>=0&&y<c){
		 			
		 			if(a[x][y]=='#'){
		 				ckl[x][y]=ckl[xx][yy]-1;
		 				if(ckl[x][y]<0)continue;//可以等于0噢 if(ckl[xx][yy]<=0)continue;
		 				if(vis[x][y])continue;
		 				else{
		 					Q.push(node(x,y,p.step+1));
		 					vis[x][y]=1;
						 }
					}
		 			else {
		 				ckl[x][y]=ckl[xx][yy];
		 				if(ckl[x][y]<0)continue;
		 				if(vis[x][y])continue;
		 				else{
		 					Q.push(node(x,y,p.step+1));
		 					vis[x][y]=1;
						 }

					 }
				 }
			 }
		 }
	}
		 cout<<"-1"<<endl;
}
int main(){//r,c,k数据范围很大设置标志数组可能会超内存 
	ios_base::sync_with_stdio(0);

	cin>>r>>c>>k;
	memset(vis,0,sizeof(vis));
		memset(ckl,0,sizeof(ckl));
	 for(int i=0;i<r;i++){
	 	for(int j=0;j<c;j++){
	 		cin>>a[i][j];
	 		if(a[i][j]=='@'){
	 			Q.push(node(i,j,0));
	 			ckl[i][j]=k;
	 			vis[i][j]=1;
			 }
		 }
	 }
	 bfs();

    return 0;
} 

而且有一个测试案例明明可以到达终点却返回了-1,说明终点没能成功入队呀。回顾三维判重数组的问题,某位置的节点是可以重复入队扩展的,什么样的节点呢?只是查克拉数目变了就可以再次入队,当然是查克拉数目在该点变多 才可能继续走下去,那某位置的节点查克拉数目怎么会增大呢?
一开始我构想,从节点a出发,到达拓展节点bs,如果b是#,查克拉数目减一,如果b是’.’,查克拉数目不变,那么接下来就算继续拓展又到达了a那么查克拉数量也一定不会大于a原来的ckl’数量呀
这么想就狭隘了

回顾一下,BFS是一次记录所有的路,所以需要设置判重标志来避免从多条路都到达 a
节点导致每次都重复去拓展a节点,归根结底判重标记就是判断从不同的路走到a节点需不需要从a节点拓展。那么这道题中,从不同的路到达a节点时查克拉的数量就很多样了,因为在不同的路中途碰见的# 数目不同,所以可能到达a节点时ckl数目不同,那么第一条路走到a节点时,路径时最短的,但查克拉剩余数量不一定是最多的,可能遇到了很多# ,此时a节点第一次入队拓展,但当从另一条更远的路走到a节点可能遇到的# 比最短的路要少且剩余ckl数目更多时,要继续从a节点出发寻找路径

就是说,bfs是多条路同时推进的,但是一般情形是最先到达x节点的那条路将x节点标记为到过,别的路就不再考虑这个节点了
但是这题不止最短路一个限制条件,还要考虑查克拉,可能别的路到达x节点时的查克拉不同(不同的所有情况里就包含了大于最先到x那条路到达x时的查克拉数,小于自然会筛掉),这时节点x要再次入队

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值