您的位置:首页 > 其它

广度优先搜索--抓住那头牛(poj 3278)

2017-11-26 10:52 337 查看
描述

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入两个整数,N和K
输出一个整数,农夫抓到牛所要花费的最小分钟数
样例输入
5 17


样例输出
4


广度优先搜索算法如下:(用QUEUE)

(1)
把初始节点S0放入Open表中;

(2)
如果Open表为空,则问题无解,失败退出;

(3)
把Open表的第一个节点取出放入Closed表,并记该节点为n;

(4)
考察节点n是否为目标节点。若是,则得到问题的解,成功退出;

(5)
若节点n不可扩展,则转第(2)步;

(6)
扩展节点n,将其不在Closed表和Open表中的子节点(判重)放入Open表的尾部,并为每一个子节点设置指向父节点的指针(或记录节点的层次),然后转第(2)步。 

先看一个广搜遍历:

#include <iostream>
#include <queue>
#define NUM 100

using namespace std;

//广度优先搜索算法如下:(用QUEUE)
//(1) 把初始节点S0放入Open表中;
//(2) 如果Open表为空,则问题无解,失败 退出;
//(3) 把Open表的第一个节点取出放入 Closed表,并记该节点为n;
//(4) 考察节点n是否为目标节点。若是, 则得到问题的解,成功退出;
//(5) 若节点n不可扩展,则转第(2)步;
//(6) 扩展节点n,将其不在Closed表和 Open表中的子节点(判重)放入Open表的尾部 ,
//并为每一个子节点设置指向父节点的指针( 或记录节点的层次),然后转第(2)步。

int Graph[NUM][NUM];
int N,M;//顶点数和边数;
bool visit[NUM] = {false};//标记已经访问过的顶点;

void BFS(int k)
{
visit[k] = true;
queue<int> q;
//把初始节点S0放入Open表中;
q.push(k);
// 如果队列表为空,则问题无解,失败 退出;
while(!q.empty()){
// 把Open表的第一个节点取出;
int temp = q.front();
printf("%c ",temp+'a'-1);
q.pop();
for(int i = 1;i<=N;i++){
if(Graph[temp][i]==1&&!visit[i]){
visit[i] = true;
q.push(i);
}
}

}
}

int main()
{
cin>>N>>M;
for(int i =1;i<=M;i++){
char a,b;
cin>>a>>b;
int x = a-'a'+1;
int y = b-'a'+1;
Graph[x][y] = Graph[y][x] = 1;
}

//针对非连通图
for(int i = 1;i<=N;i++)
if(!visit[i])
BFS(i);
cout <<endl;
return 0;
}

//8 14
//a b
//a c
//a e
//a f
//a g
//a h
//b d
//b e
//b h
//c g
//c h
//d h
//e f
//f g

   //这道题注意:

//1.这种图是无法用数据结构来存储的,这是一种未知的图;不过他的顶点个数可以得到;并且是每两个顶点之间的位置直接就可以知道的,

//这是由关系来却定的,所以在入队列的时候直接就是将其找到其邻接顶点,直接就入队了,这种能直接找到邻接顶点的直接就是开始广搜

//,不需要储蓄,因为存储的目的也就是为了将每一邻接的顶点找到,如果能直接省略的储存就直接省略了,

//2,在使用广搜的时候可能要求解其中的步数,这个时候可以将入队列的类型是一个结构体,这样在入队列的时候直接就可以将其+1,就可以将

//步数计算的到;

这道题的代码:

 #include <iostream>
#include <queue>
#define NUM 100000

using namespace std;
int N,K;
bool visted[NUM+10];

struct Step{
int i;
int step;
Step(int x,int s):i(x),step(s){};//默认构造函数;
};

void BFS()//过程和层序遍历二叉数一样的;不一样就是二叉树只有两个邻接顶点,这是确定的;
{
queue<Step> q;

q.push(Step(N,0));//农夫最初的位置;
visted
= true;
while(!q.empty()){
Step s = q.front();//获取第一个顶点的值
q.pop();
if(s.i == K){
cout<<s.step<<endl;
return ;
}
else{//第一个顶点的邻接顶点入队;等待按照一层一层的输出;
if( s.i - 1 >= 0 && !visted[s.i-1] ) {
q.push(Step(s.i-1,s.step+1));
visted[s.i-1] = true;
}
if( s.i + 1 <= NUM && !visted[s.i+1] ) {
q.push(Step(s.i+1,s.step+1));
visted[s.i+1] = true;
}
if(s.i*2<=NUM&&!visted[s.i*2]){
q.push(Step(s.i*2,s.step+1));
visted[s.i*2] = true;
}
}
}
}

int main()
{
cin>>N>>K;
BFS();
return 0;
}


ps:我的很多题是用STL来解题的,如果不只到C++STL可以先去了解怎么用,相信你会喜欢他,因为很多题目一位有了他变得更简单;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息