搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1728

BFS:从一个图的某个顶点出发,首先访问与v节点相邻切未被访问过的节点v1,v2,v3,v4..... ,然后依次访问与v1,v2,v3,v4...相邻且未被访问过的节点,

 由此可以得到 BFS进行搜索所搜索的节点都是按深度进行扩展的,先找到到V0距离为1的所有节点,然后找到距离V0为2的节点……所以BFS所搜索到的都是最短的路径。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
char map[105][105];
int n, m;
struct node
{
    int i, j;
    int step; //保存转弯数
} q, p;
int x2, y2, k;
bool v[105][105];
int move[4][2]= {1, 0, -1, 0, 0, 1, 0, -1};
bool pan(int x, int y) //判断坐标是否ok 
{
    if(x<0 || x>=n || y<0 || y>=m) return false;
    if(map[x][y]=='*')  return false;
    return true;
}
bool BFS(node q) 
{
    queue<node> Q;
    Q.push(q);
    memset(v, 0, sizeof(v));
    v[q.i][q.j]=1;
    while(!Q.empty())
    {
        q=Q.front();
        Q.pop();
        if(q.step >= k) continue;
        for(int i=0; i<4; i++)
        {
            p.i=q.i+move[i][0];
            p.j=q.j+move[i][1];
            p.step=q.step+1;
            while(1) //从一个方向往下搜索
            {
                if(!pan(p.i, p.j))  break;
                if(p.i==x2&&p.j==y2) return true;
                if(!v[p.i][p.j])  //遇到没有标记的进行标记
                {
                    v[p.i][p.j]=1;
                    Q.push(p);
                }
                p.i += move[i][0];
                p.j += move[i][1];
            }
        }
    }
    return false;
}
int main()
{
    int t, i;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(i=0; i<n; i++)
            scanf("%s", map[i]);
        scanf("%d%d%d%d%d", &k, &q.j, &q.i, &y2, &x2);
        q.j--, q.i--, x2--,y2--; //地图上是(0,0)开始的
        q.step=-1; //第一次选择方向时,没有转弯
        if(BFS(q)) puts("yes");
        else puts("no");
    }
    return 0;
}

DFS:可以看出是尽可能“深”的在图中进行搜索。 如果被访问的节点还有相邻的节点且未被访问,则访问此节点,如果找不到,则返回被访问节点的上一个节点。这一过程一直进行直到所有的节点都被访问为止。 DFS可以搜索出从某一个节点到另外的一个节点的所有路径。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define M 0x7fffffff
int x_m[4] = {0, 1, 0, -1};
int y_m[4] = {1, 0, -1, 0};
int x2, y2, k, n, m, flag;
char map[105][105];
int v[105][105];
void DFS(int x, int y, int f)
{
    if(x==x2 && y==y2)  //当前坐标达到目标点
    {
        if(v[x][y] <= k)
            flag = 1;
        return ;
    }
    if(v[x][y] > k) return ; //当前坐标时的转弯数 大于 限定值
    if(v[x][y]==k && x!=x2 && y!=y2) return ;//这里x,y之间不能用‘或’自己体会
    for(int i=0; i<4; i++)
    {
        int tx = x+x_m[i];
        int ty = y+y_m[i];
        if(tx<0 || tx>=m || ty<0 || ty>=n) //越界则想下一个方向进行
            continue;
        if(v[tx][ty] < v[x][y] || map[tx][ty] == '*') //当前状态不能行走时
            continue ;
        if(f!=-1 && f!=i && v[tx][ty] < v[x][y]+1)  //当前状态的点转的弯数比上一状态+1还少
            continue;
        v[tx][ty] = v[x][y];
        if(f!=-1 && i!=f) v[tx][ty]++;
        DFS(tx, ty, i);
        if(flag) return ;
    }
}
int main()
{
    int t, i, x1, y1, j;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &m, &n);
        for(i=0; i<m; i++)
            scanf("%s", map[i]);
        scanf("%d%d%d%d%d", &k, &y1, &x1, &y2, &x2);
        x1--,x2--,y1--,y2--;
        for(i=0; i<m; i++) //未走的点的弯数标记为无穷大
            for(j=0; j<n; j++)
                v[i][j] = M;
        v[x1][y1] = 0;
        flag = 0;
        DFS(x1,y1,-1);
        printf("%s\n", flag ? "yes" : "no");
    }
    return 0;
}

知识:

头文件 #include<queue>
队列:
queue<类型> Q;
Q.push(a)       数据a接入队尾
Q.pop()           弹出队列第一个元素
Q.front()          返回队首元素
Q.back()          返回队尾元素
Q.empty()        判断队列是否为空 空返true
Q.size()           返回队列元素
 
优先队列:
操作中没有front,
top返回优先级最大的
Q.top()  其余不变 
初始化队列
1.系统默认优先级(大->小)
 priority_queue<int> qi;
2. 自定义优先级
结构体
struct node
{
    friend bool operator< (const node &n1, const node &n2)
    {
        return n1.priority > n2.priority;  //小的先出队
   }
    int priority;
    int value;
};
priority_queue<node> qi;

还有一种运用另一个函数的,感觉先把这两种弄懂再说~~

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1242

大意:一个n*m 的牢房,#代表墙,a代表目标,r代表起点,x代表守卫。每走一步需要1点能量,每打败一个守卫需要1点能量。 从起点到目标点需要最小能量  不能达到则输出
   “Poor ANGEL has to stay in the prison all his life.”
思路:这个有个达到守卫需要能量,so BFS+优先队列~~
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct nn //节点结构
{
    int i, j, step;
    friend bool operator < (const nn &a, const nn &b) //定义优先队列 小的先出队
    {
        return a.step > b.step;
    }
};
//行,列 可以走的坐标点
int i_m[4] = {0, 1, 0, -1};
int j_m[4] = {-1, 0, 1, 0};
int n, m;
int v[205][205], step;
char map[205][205];
void BFS(int x1, int y1) //需要最短步骤,so用BFS 且 要用优先队列应为遇到敌人时打败需要时间。
{
    priority_queue<nn> Q;
    memset(v, 0, sizeof(v));
    step = -1;   //初始化
    nn q, p;
    q.i = x1;
    q.j = y1;
    q.step = 0;
    Q.push(q);   //将起点入队
    v[x1][y1] = 1;
    while(!Q.empty())
    {
        q = Q.top(); //拿出队首元素
        Q.pop();
        if(map[q.i][q.j] == 'a') //当前点是目标点
        {
            step = q.step;
            return ;
        }
        for(int i=0; i<4; i++)
        {
            p.i = q.i+i_m[i];
            p.j = q.j+j_m[i];
            if(0<=p.i && p.i<n && 0<=p.j && p.j<m && !v[p.i][p.j] && map[p.i][p.j]!='#') //当前点符合要求
            {
                if(map[p.i][p.j]=='x')
                    p.step = q.step+2;
                else p.step = q.step+1;
                v[p.i][p.j] = 1;  //将当前点进行标记
                Q.push(p);        //当前点入队列
            }
        }
    }
}
int main()
{
    int i, j, x1, y1;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        for(i=0; i<n; i++)
            scanf("%s", map[i]);
        for(i=0; i<n; i++)
            for(j=0; j<m; j++)
                if(map[i][j] == 'r')
                {
                    x1 = i;
                    y1 = j;
                    break;
                }
        BFS(x1,y1);
        if(step == -1)
            printf("Poor ANGEL has to stay in the prison all his life.\n");
        else  printf("%d\n", step);
    }
    return 0;
}
 
 
大意:一个8*8的棋盘,遵循象棋中‘马’的走法。给你起点和终点,问最少需要多少步可以到达~
思路: 需要求最少 即BFS。
 
 
 
posted @ 2015-09-22 16:51  马晨  阅读(105)  评论(0)    收藏  举报