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

来源:互联网 发布:派拉软件 编辑:程序博客网 时间:2024/05/21 02:20
描述

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点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 100using 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 100000using 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[N] = 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可以先去了解怎么用,相信你会喜欢他,因为很多题目一位有了他变得更简单;




原创粉丝点击