备战蓝桥杯决赛----坚持第四天!!!
又是一个深夜。。。昨天说今天要找一些关于BFS和DFS的练习题,今天当然是要怎么做。但是,我仅仅做了两道题,全来自于蓝桥杯练习题库。再看看所用时间,发现自己的效率是真的不高。。(一直以来的问题,还没有找到好的办法解决)
那就说下这两道题目吧,说完还要洗洗睡觉。。。
首先是一道关于BFS的练习题
接下来n行,每行m个数,数之间没有间隔,为0或1中的一个。0表示这个格子可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫的出口在(n,m)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)可以通过。
第二行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。
3 3
001
100
110
Input Sample 2:
3 3
000
000
000
4
RDRD
Output Sample 2:
4
DDRR
有50%的数据满足:1<=n,m<=50
有100%的数据满足:1<=n,m<=500。
思路:通过bfs寻找一条可从起点到达终点的最短路径,但是这里附件了一个条件:如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。这才是值得思考的地方,既然需要字典序最小,那么我们首先对四个方向进行字典序排序,排序结果为:DLRU。那么我们在进行bfs搜索时,按照这个排序方向的先后顺序,进行搜索,这样最终确定的一定是一个字典序最小的路径。
附程序代码及重要注释:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAX=501;//有100%的数据满足:1<=n,m<=500。因为我们使用时从1,1开始,所以数组长度为501
struct pos{
int x;
int y;
int sum;
};
int dict[4][2]={{1,0},{0,-1},{0,1},{-1,0}};//这里数组表示的是与字典序对应操作DLRU所产生的结果,二维数组中两个元素分别代表行(1下移0不动-1上移)和列(1右移0不动-1左移)
//的变化。其实很好理解,想两遍就通了
char str[5]="DLRU";//详细说明见下面常识一
int pre[MAX][MAX];
char temp[MAX][MAX];
int vis[MAX][MAX];
int n;
int m;
void bfs(){
queue<pos> q;
memset(vis,0,sizeof(vis));
pos p;
p.x=1;
p.y=1;
p.sum=0;
q.push(p);
vis[1][1]=1;
pre[1][1]=-1;//设置其实点的pre为-1,不存在
while(!q.empty()){
p=q.front();
q.pop();
if(p.x==n&&p.y==m){
cout<<p.sum<<endl;
return;//此时一定要return空结束循环
}
pos pp;
for(int i=0;i<4;i++){
pp.x=p.x+dict[i][0];
pp.y=p.y+dict[i][1];
pp.sum = p.sum+1;
if(pp.x>=1&&pp.x<=n&&pp.y>=1&&pp.y<=m&&temp[pp.x][pp.y]=='0'&&vis[pp.x][pp.y]==0){
vis[pp.x][pp.y]=1;
pre[pp.x][pp.y]=i;
q.push(pp);
}
}
}
}
void path(int x,int y){
if(x==1&&y==1){
return;
}
path(x-dict[pre[x][y]][0],y-dict[pre[x][y]][1]);//输出时,我们反向寻找,从终点寻找到起点
cout<<str[pre[x][y]];//递归到起点位置,每次返回上一层时,打印对应操作字符,即又变成从起点到终点的动作
}
int main () {
cin>>n>>m;
getchar();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>temp[i][j];
}
getchar();//详细说明见下面常识二
}
bfs();
path(n,m);
return 0;
}
另外,想在此题下面补充两个常识(其实就是之前忘记的知识点)
常识一:
char str[]="abcd"与char str[]={'a','b','c','d'}一样吗?char str[]="abcd" 等价于 char str[]={'a','b','c','d','\0'},实际上占用5bytes内存。
char str[]={'a','b','c','d'} 占用4bytes内存。
常识二:
getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,1.从缓冲区读走一个字符,相当于清除缓冲区2.前面的scanf()在读取输入时会在缓冲区中留下一个字符'\n'(输入完s[i]的值后按回车键所致),所以如果不在此加一个getchar()把这个回车符取走的话,gets()就不会等待从键盘键入字符,而是会直接取走这个“无用的”回车符,从而导致读取有误3.getchar()是在输入缓冲区顺序读入一个字符(包括空格、回车和Tab)getchar()使用不方便,解决方法: (1)使用下面的语句清除回车: while(getchar()!='\n'); (2)用getche()或getch()代替getchar(),其作用是从键盘读入一个字符(不用按回车),注意要包含头文件<conio.h>
然后是关于DFS的一道例题
问题描述
很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。
聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。
J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数
城市从1开始依次编号,1号城市为首都。
接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)
每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。
输出格式
输出一个整数,表示大臣J最多花费的路费是多少。
样例输入1
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出1
135
输出格式
大臣J从城市4到城市5要花费135的路费。
解题思路:其实这是一道非常简单的搜索类型题目,关键点是如何判断出深搜时最长的一条路?其实,像这种题目,是存在一个知识点的,即这题就是让求:树的直径(树上最长的简单路径即为树的直径。求树的直径的方法就是在树上任选一点u,求距离点u最远的点y,再求距离点y最远的点s,点y到点s的距离即为树的直径。)这样,我们很明确得出:树的直径即为最长路径。
另外我们做题之前还要考虑一个经验性问题,就是这个题目,并没有个数据范围,比如:城市数目,即节点数目。所以我们构建图时,需要设定一个范围非常大的图,所以我们要使用邻接表表示图节点之间的联系
附程序代码及重要注释:
#include <iostream>
#include <cstring>
#include<vector>
using namespace std;
const int MAX=10005;
int visit[MAX];
int len,n,st;
struct node{ //构建与某节点相连的节点及权值
int v,w;
node(int vv,int ww){
v=vv;
w=ww;
}
};
vector<node> vt[10005]; //将数组定义为10005,基本就满足“很大”这个条件了
void getValue(int len){
cout<<(10*len+(len*(1+len)/2));
}
void dfs(int u,int cur){
if(len<cur){
len=cur;
st=u;
}
int l=vt[u].size();
for(int i=0;i<l;i++){
int v=vt[u][i].v;
int w=vt[u][i].w;
if(!visit[v]){
visit[v]=1;
dfs(v,cur+w);
}
}
}
int main () {
int x,y,z;
memset(visit,0,sizeof(visit));
cin>>n;
for(int i=0;i<n-1;i++){
cin>>x>>y>>z;
vt[x].push_back(node(y,z)); //无向图,插入两边节点
vt[y].push_back(node(x,z));
}
len=0;
visit[1]=1;
dfs(1,0);
len=0;
memset(visit,0,sizeof(visit));//一定要记得清空节点访问记录
visit[st]=1;
dfs(st,0);
getValue(len);
return 0;
}
当然,对于这种初级的dfs,我们也可以改成栈优化的dfs,这里不做介绍,自己可以尝试
上一篇: java反射获取get/set方法
下一篇: 支持排序功能的oracle分页