2

基础搜索算法的常见题型

重点:这是一份课件整理,出自杨乐大佬之手,就此声明。

首先,搜索是一种暴力,在数据范围小的情况下,枚举所有的可能性。我们来模拟处理问题的步骤。

搜索主要分两类:dfs(深度优先搜索)

       :bfs(广度优先搜索)

dfs的经典例题:

范式:

void dfs(_position_,_state_)
if _success_ then _goal_
else
    for every possible _move_//枚举每一种可能行动
    if _acailable_ then//如果没有违法约束
       _new_state_=(_state_,_move_)//计算新的状态
       _new_possible_=nexr_position_ //计算下一个阶段
       dfs(_new_position_,_new_state_)//进行下一步的搜索

 

1.数独问题

题目梗概:给出一个 9×9 的棋盘,上面已经填好了部分数字。要 求补充完整个棋盘,并且使得每行、每列、每个 3×3 小方阵内没 有重复的数字。
* 分析数独问题: 1 “划分游戏阶段”:从左到右从前到后,决定每一个空格的数字

         2“行动”:对于某一个特定的空格,枚举上面填什么数字

         3* “胜利”:全部填完了之后,判断这个填的方法是否符合条件

 

#include<iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 9;
const int Group[9][9] = 
{
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    6, 6, 6, 7, 7, 7, 8, 8, 8,
    6, 6, 6, 7, 7, 7, 8, 8, 8,
    6, 6, 6, 7, 7, 7, 8, 8, 8
};

int a[N][N];
int row[N][N], col[N][N], gr[N][N];


void print()
{
    printf("One Possible Solution:\n");
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++) printf("%d ", a[i][j] + 1);
        printf("\n");
    }
}
void dfs3(int x, int y)
{
    if(x == N)
    {
        print();
        return;
    }

    int next_x = x, next_y = y + 1;
    if(next_y == N) next_x = x + 1, next_y = 0;//提前将下一步的位置处理好 

    if(a[x][y] >= 0) dfs3(next_x, next_y);//已经填好数了,那么我就跳过 
    else
    {
        for(int i=0; i<N; i++)
            if(!row[x][i] && !col[y][i] && !gr[Group[x][y]][i])
            {
                row[x][i] = col[y][i] = gr[Group[x][y]][i] = 1;

                a[x][y] = i;//这个数没有出现过,就让它等于当前数 并标记 
                dfs3(next_x, next_y);
                a[x][y] = -1;

                row[x][i] = col[y][i] = gr[Group[x][y]][i] = 0;
            }
            /*每到一个位置,枚举每一个数,如果该数行,列,小正方都不重复,则填入
            继续搜索下一个,之后便是回溯一步*/ 
    }
}

int main()
{


    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
            scanf("%d", &a[i][j]), a[i][j]--;//因为我们从0开始存 

    printf("Dfs Method3:\n");

    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
            if(a[i][j] >= 0) 
                {
                    row[i][a[i][j]] = 1;
                    col[j][a[i][j]] = 1;
                    gr[Group[i][j]][a[i][j]] = 1;
                }
        /*把每一行每一列,每一小方块的已经给出的数全部标记为,
        而这个group就是来判定这个位置是属于哪一个小方块的*/
/*        printf("row:\n");
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++) printf("%d ", row[i][j]);
        printf("\n");
    }
    printf("********************\n");
        printf("col:\n");
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++) printf("%d ", col[i][j]);
        printf("\n");
    }
    printf("********************\n");
        printf("gr:\n");
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++) printf("%d ", gr[i][j]);
        printf("\n");
    }
    printf("********************\n");    
    如果对col,row,gr的定义还是不大懂的话,可以解锁以上程序加以理解*/
    dfs3(0, 0);

    return 0;
}

 

 

 

* 分析背包问题: 1 “划分游戏阶段”:从第一个物品开始,考虑它的选取情况

         2 “行动”:对于某一个特定的物品,考虑它选不选

         3* “约束”:选取完成后,还需要判断它是否能装得下

        4* “最优方案”:如果可以装得下,我们需要选择一 个价值之和最大的

 

#include<iostream>
#include<cstdio>
using namespace std;
int w[1001],v[1001],n;
int ans,t;
void dfs(int x,int totw,int totv)
{
    if(x>n)
    {
        if(totw>ans)
            ans=totw;
        return ;
    }
    else
    {
        dfs(x+1,totw,totv);
        if(totv+v[x]<=t)
        dfs(x+1,totw+w[x],totv+v[x]);
    }
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&w[i],&v[i]);
    dfs(1,0,0);
    printf("%d",ans);
    return 0;
}

 

对于这个问题我们来拓展一下:

1.如何记录拿了几件

//多定义一个a[1001] b[1001]
void dfs(int x,int totw,int totv)
{
    if(x>n)
    {
        if(totw>ans)
            {
                for(int i=1;i<=a[0];i++)
                b[i]=a[i];
                ans=totw;
            }
        return ;
    }
    else
    {
        dfs(x+1,totw,totv);
        if(totv+v[x]<=t)
        {
            ++a[0],a[a[0]]=x;
            dfs(x+1,totw+w[x],totv+v[x]);
            a[a[0]]=0,--a[0];
            //用a[0]来记录拿的个数 这个 也算一个技巧
        }
    }
}

 

2.完全背包(取无数件)

void dfs(int x,int totw,int totv)
{
    if(x>n)
    {
        if(totw>ans)
            ans=totw;
        return ;
    }
    else
    {
        dfs(x+1,totw,totv);
        while(totv+v[x]*m<=t)
        {
        dfs(x+1,totw+w[x]*m,totv+v[x]*m);
        m+=1;
        }
    }
}

3.多重背包:给了规定件数可以取,求最大价值

void dfs(int x,int totw,int totv)
{
    if(x>n)
    {
        if(totw>ans)
            ans=totw;
        return ;
    }
    else
    {
        dfs(x+1,totw,totv);
        for(int i=1;i<=member[x];i++)
        {
            if(totv+v[x]*i<t)
        dfs(x+1,totw+w[x]*i,totv+v[x]*i);
        m+=1;
        }
    }
}

当然,我们这里都是最最基本的搜索,欢迎补充优化

 

* 分析哈密顿回路问题: 1 “划分游戏阶段”:走到了哪一个点

            2 “行动”:下一步走哪一个点

            3* “胜利”:把全部点都走遍了

            4* “约束”:在过程中有没有走到重复的点

 

#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 25;

int n, cnt;
int a[N][N];
int v[N], p[N];

void print()
{
    printf("Route #%d: ", ++cnt);
    for(int i=1; i<=p[0]; i++) printf("%d - ", p[i]);
    printf("1\n");
}

void dfs(int x)
{
    v[x] = 1, p[++p[0]] = x;//记录走的那几个点 

    if(p[0] == n)
    {
        if(a[p[0]][1]) print();//如果头和尾也相连,输出 
    }
    else for(int i=1; i<=n; i++) 
            if(a[x][i] && !v[i])//有路径并且没有走过->搜索 
                dfs(i);
    
    v[x] = 0, p[p[0]] = 0, --p[0];//回溯 
}

int main()
{
//    freopen("hamilton.in", "r", stdin);
//    freopen("hamilton.out", "w", stdout);

    scanf("%d", &n);
    for(int i=1; i<=n; i++) 
        for(int j=1; j<=n; j++) 
            scanf("%d", &a[i][j]);//用邻接矩阵来存储的哈密尔顿环 

    dfs(1);

    return 0;
}

 

*POJ 1979  红与黑:考虑 问题的各个步骤
  1 阶段/ 搜索顺序:一步一步的走
  2 状态:目前走到的位置
  3 行动:向上下左右各走一步
  4 胜利条件/ 结束条件:没有地方可以走了
  5 约束:不能走出房间/ 不能走到红色瓷砖上

 

#include <cstdio>
using namespace std;

const int N = 25;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

int n, m, sx, sy, cnt;
int a[N][N], vs[N][N];

void dfs(int x, int y)
{
    ++cnt, vs[x][y] = 1;//计数加标记 
    for(int d=0; d<4; d++)
    {
        int i=x+dx[d], j=y+dy[d];//上下左右四个方向 
        if(i<1 || j<1 || i>n || j>m || a[i][j]=='#' || vs[i][j]) continue;
        //不越界,不违法约束 
        dfs(i, j);
    }
}
//当然,这道题用bfs也可以做,但都差不多 
int gc()
{
    int c;
    while(c=getchar(), c<=' ');
    /*先输入数据,之后getchar()的返回值一个接一个赋给c,
     然后比较c是不是不等于' ',如果不等于回车键就会执行循环。
     如果等于就会结束*/ 
     //相当于用输入字符矩阵 
    return c;
}

void work()
{
    for(int i=1; i<=n; i++) 
        for(int j=1; j<=m; j++)
    {
        a[i][j] = gc(), vs[i][j] = 0;
        if(a[i][j]=='@') sx = i, sy = j;//标记所给位置 
    }
    /*
    ch=getchar();等待从键盘上输入一个字符
    putchar(ch);输出此字符
    他们包含在头文件 #include<stdio.h>中.
    */ 
    cnt = 0;
    dfs(sx, sy);//从所给位置开始搜索 
    printf("%d\n", cnt);
}

int main()
{
    freopen("rnb.in", "r", stdin);
    freopen("rnb.out", "w", stdout);
    
    while(scanf("%d%d", &m, &n), n*m) work(); 
    //且m!=0||n!=0 ,当然它的数据是保证合法的 
    //用while循环输入,它的输入输出端是自动连在文件上的,
    //所以用键盘输入是不会有结果的 
    
    return 0;
}

 

DFS小总结:* 问题的各个步骤:
      1 阶段/ 搜索顺序    

      2 状态:全局状态记得回溯(有的不需要)   

      3 行动:枚举所有可能的行动
      4 胜利条件/ 结束条件
      5 约束

下面我们来看BFS(前方高能预警)

 

* BFS 搜索的思想是十分简单的: - 给定一个起始状态(将其记作 S0);

           - 记录从起始状态向外走一步能到达的状态(我们把它记作 S1);

           - 记录从 S1 走一步能到达的状态(将它们记作 S2);

           显然,这些 状态都能从起始状态走两步到达。

           * 最终,如果目标状态出现在 Sk 中,则显然它可以从起始状态 走k 步到达(所以最终答案是最小的 k)。

           * 我们称这种做法为逐步扩展

 

八数码

题目太经典就不显示了,而且这道题目曾经搞的我一晚上也没睡好,所以我今天一定要把它办掉

八数码问题的状态即为棋盘上的八个数字

从每一个空格开始上下左右各一种可能

扩展出第一种状态,依次类推

补充一点,bfs 是用队列来实现的

但有一个很重要的问题就是 :如何判重,以及哪些是重复的。

(好像这里有图的样子)

 

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
    printf("1 2 3\n");
    printf("5   6\n");
    printf("7 8 9\n");
    cout<<"---->"
    printf("         1 2 3\n");
    printf("         5 6  \n");
    printf("         7 8 9\n");
    //那么把从这个空格开始向四个方向扩展,必定有一种情况是这样的
    printf("1 2 3\n");
    printf("5   6\n");
    printf("7 8 9\n");
    //这样就回到原来的状态了,即为重复
    //而我们要克服的就是这些 
} 

 

接下来我们从程序入手

本来应该是三步优化,一步比一步快,但我想,我写的既然是一个总结帖,我为什么不直接把最优的展示出来能?(好像很有道理的样子)


其实是我懒

 

 下面我们看程序

struct _state
{
    int w[N][N];//当前这个棋盘的状态
    int x, y;//该空格的位置
    int step;//走了几步
    int pre, dirc;//父亲和对应的操作

如何判重?

如果我们开一个九维数组的话,哪怕是开bool型的,有以下几个麻烦之处

1.写起来麻烦

2.存起来费空间

3.查找起来费时间

4.看着别扭

综上所述,我们聪明的前辈想到了一种很不错的存储办法,

------>用一个九位数来存

这样只需要int就足够了

像这样:

    int calc()
    {
        int ret = 0;
        for(int i=0; i<N; i++)
            for(int j=0; j<N; j++)
                ret = ret * 10 + w[i][j];
        return ret;
    }

那么程序实现就是

int bfs(_state start, _state end)
{
    head = tail = 1;
    start.step = 0;
    start.pre = -1;
    queue[1] = start;
    
    S.clear();
    S.insert(start.calc());

    for(; head<=tail; ++head)
    {
        _state cur = queue[head];
        int x = cur.x, y = cur.y;

        for(int i=0; i<4; i++)
        {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx<0 || ny<0 || nx>=N || ny>=N) continue;
                        //枚举上下左右四个位置
            _state now = cur;//新的状态
            now.x = nx, now.y = ny;//新的空格位置
            swap(now.w[x][y], now.w[nx][ny]);//交换位置
            now.step++;//步数+1
            now.pre = head;//记录父亲
            now.dirc = i;//操作:空格移动的方向

            int nst = now.calc();
            if(S.find(nst) == S.end())//用set的一个判重,下面会讲:如果没有重复的数字
                queue[++tail] = now,//加入队列
                S.insert(nst);//并标记该状态

            if (equal(now,end)) return tail;
        }
    }

    return -1;
}
            

补充一点:set是个神马东东

 

 set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与右子树的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

        平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

        构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include<set>”。

 

采用inset()方法把元素插入到集合中,插入规则在默认的比较规则下,是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。使用前向迭代器对集合中序遍历,结果正好是元素排序后的结果。

下面我先放一波程序

 

#include <set>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 3;
const int M = 1e6 + 5;

const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};//四个方向搜索的小技巧
const char mov[4] = {'R', 'L', 'D', 'U'};

struct _state
{
    int w[N][N];
    int x, y;
    int step;
    int pre, dirc;

    void read()//读入矩阵并存储空格位置
    {
        for(int i=0; i<N; i++)
            for(int j=0; j<N; j++)
            {
                scanf("%d", &w[i][j]);
                if(!w[i][j]) x=i, y=j;
            }
    }

    int calc()//将矩阵改为一个九位数
    {
        int ret = 0;
        for(int i=0; i<N; i++)
            for(int j=0; j<N; j++)
                ret = ret * 10 + w[i][j];
        return ret;
    }
};

int equal(_state x, _state y)//
{
    for(int i=0; i<N; i++)
     for(int j=0; j<N; j++)
        if(x.w[i][j] != y.w[i][j]) return 0;
    return 1;
}

_state queue[M];
set<int> S;

int head, tail;

int bfs(_state start, _state end)//开始状态,结束状态各有两个矩阵来表示
{
    head = tail = 1;//队列为空
    start.step = 0;//初始步骤为零
    start.pre = -1;//初始状态没有父亲
    queue[1] = start;//初始状态入队

    S.clear();//清空set
    S.insert(start.calc());//插入这个矩阵所转化为的九位数

    for(; head<=tail; ++head)//如果队列不为空
    {
        _state cur = queue[head];//取队首
        int x = cur.x, y = cur.y;//复制空格位置

        for(int i=0; i<4; i++)
        {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx<0 || ny<0 || nx>=N || ny>=N) continue;

            _state now = cur;
            now.x = nx, now.y = ny;
            swap(now.w[x][y], now.w[nx][ny]);//拓展空格位置
            now.step++;
            now.pre = head;//记录是第几步
            now.dirc = i;//从哪个方向拓展来的

            int nst = now.calc();
            if(S.find(nst) == S.end())//end()返回集合里最后一个元素的迭代器
                      //返回指向被查找元素的迭代器
    //find()可以查找一个元素在集合里的迭代器,如果该元素未出现过,则返回end() queue[
++tail] = now,//(注意是逗号)使该元素入队 S.insert(nst); if (equal(now,end)) return tail;//如果该矩阵已经和要求矩阵一样了 } } return -1; } int seq[N]; void print(int no, int x) { printf("Step #%d\n", x); for(int i=0; i<N; i++) { for(int j=0; j<N; j++)
       printf("%d ", queue[no].w[i][j]);//输出当前步数下的矩阵 printf("\n"); } } int main() { //freopen("eight.in", "r", stdin); // freopen("eight.out", "w", stdout); _state start, end; start.read(); end.read(); int ans = bfs(start, end); printf("%d\n", queue[ans].step);

s:
for(int i=tail; i>=0; i=queue[i].pre) seq[++seq[0]] = i;//用s[0]来存储个数 for(int i=seq[0]; i>=1; i--) print(seq[i], seq[0]-i);//输出矩阵
printf(
"Moving Sequence: \n"); for(int i=seq[0]-1; i>=1; i--) printf("%c", mov[ queue[seq[i]].dirc ]);//输出该矩阵的操作 return 0; }

 注意,bfs是逐层扩展的,相当于给第一次一个编号,给第二层一个编号。。。。。。

不要与dfs混淆

下面我们看跳马问题

跳马就是八个方向遍历,然后判重,如程序

#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 303;
const int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};

struct _state
{
    int x, y, step;
};

int t, n;
int sx, sy, tx, ty;
int vs[N][N];
int head, tail;
_state que[N * N];

void work()
{
    scanf("%d", &n);
    scanf("%d%d", &sx, &sy);
    scanf("%d%d", &tx, &ty);

    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++) vs[i][j] = 0;//标记初始状态全部为未走过

    head = tail = 1;
    que[head].x = sx;
    que[head].y = sy;//入队
    que[head].step = 0;//这个步数还是逐层扩展的
    vs[sx][sy] = 1;

    for(; head <= tail; ++head)
    {
        int x = que[head].x;
        int y = que[head].y;
        int step = que[head].step;

        if(x == tx && y == ty)//到达目标,输出
        {
            printf("%d\n", step);
            return;
        }

        for(int i=0; i<8; i++)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];
            int nstep = step + 1;//大佬做深/广搜题喜欢先把下一步的状态写出来,然后再判断,再入队/搜索

            if(nx<0 || ny<0 || nx>=n || ny>=n) continue;
            if(vs[nx][ny]) continue;

            ++tail;
            que[tail].x = nx;
            que[tail].y = ny;
            que[tail].step = nstep;
            vs[nx][ny] = 1;//这里就是判重,使得它必定能找到解
        }
    }
}

int main()
{
    //freopen("knight.in", "r", stdin);
    //freopen("knight.out", "w", stdout);

    scanf("%d", &t);
    for(int i=1; i<=t; i++) work();

    return 0;
}

接下来是倒水问题,

 倒水问题:有两个水壶,容积分别为 A,B。有三种操作: Fill(往一个水壶倒满水),Drop(倒出某个水壶的水),Pour(将 其中一个水壶的水倒入另一个水壶中,倒满即止)。

- 问倒出 C 升水,最少的步数是多少。

这个我们就分六步来进行讨论

设水壶a,b;

1.倒空a

2.倒空b;

3.倒满a;

4.倒满b;

5.把a倒向b(这里需要判断a,b水量)

6.把b倒向a(这里需要判断a,b水量)

具体操作如下


#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;


const int N = 103;


const string operate[6] =
{
"FILL(1)", "FILL(2)", "DROP(1)",
"DROP(2)", "POUR(1,2)", "POUR(2,1)"
};


struct _state//每一个水杯状态所含的消息
{
int x, y;
int step;
int pre, op;
};


int a, b, c;
int vs[N][N];
int head, tail;
_state que[N * N];


int seq[N];


void print(int x)
{
printf("%d\n", que[x].step);
for(int i=x; i>=0; i=que[i].pre)
seq[++seq[0]] = i;
for(int i=seq[0]-1; i>=1; i--)
printf("%s\n", operate[que[seq[i]].op].c_str());//c_str()下文有讲,

}

//总结一下这种倒向输出转移状态的步骤

/*

1.新开一个数组来倒叙存储下标

2.一个倒叙for,输出最后一步所在队列的状态,用刚才存储的下标来做

3.前提:你在进行bfs扩展时,已经存储了它的父节点,已经操作方式

*/


void add_state(int nx, int ny, int nstep, int pre, int op)
{
if(vs[nx][ny]) return;


vs[nx][ny] = 1;//标记该状态已经走过


++tail;
que[tail].x = nx;
que[tail].y = ny;
que[tail].step = nstep;
que[tail].pre = pre;
que[tail].op = op;

//入队

}


void work()
{
scanf("%d%d%d", &a, &b, &c);


for(int i=0; i<=a; i++)
for(int j=0; j<=b; j++) vs[i][j] = 0;


head = tail = 1;
que[head].x = 0;
que[head].y = 0;
que[head].step = 0;
que[head].pre = -1;
vs[0][0] = 1;//初始状态入队


for(; head <= tail; ++head)
{
int x = que[head].x;
int y = que[head].y;
int step = que[head].step;//取队首


if(x == c || y == c)
{
print(head);//正解,输出
return;
}


// Fill
add_state(a, y, step+1, head, 0);
add_state(x, b, step+1, head, 1);


// Drop
add_state(0, y, step+1, head, 2);
add_state(x, 0, step+1, head, 3);


// Pour
int aug = min(x, b - y);
add_state(x-aug, y+aug, step+1, head, 4);


aug = min(y, a - x);
add_state(x+aug, y-aug, step+1, head, 5);
}


puts("impossible");
}


int main()
{
freopen("cups.in", "r", stdin);
freopen("cups.out", "w", stdout);


work();


return 0;
}

 

补充:

函数声明:const char *c_str();

c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.

这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。

注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针

例:

应该这样用:

char c[20];

string s="1234";

strcpy(c,s.c_str());

这样才不会出错,c_str()返回的是一个临时指针,不能对其进行操作

c_str()返回的是一个分配给const char*的地址,其内容已设定为不可变更,如果再把此地址赋给一个可以变更内容的char*变量,就会产生冲突,在2010中是不被允许的。但是如果放入函数调用,或者直接输出,因为这些函数和输出都是把字符串指针作为 const char*引用的,所以不会有问题。

 

c_str() 以const char* 类型返回 string 内含的字符串

如果一个函数要求char*参数,可以使用c_str()方法:

string s = "Hello World!";

printf("%s", s.c_str()); //输出 "Hello World!"

c_str在打开文件时的用处:

当需要打开一个由用户自己输入文件名的文件时,可以这样写:ifstream in(st.c_str());。其中st是string类型,存放的即为用户输入的文件名。

bfs小结

* BFS 问题的各个步骤:

1 阶段/ 搜索顺序:题目会明确地给出

2 状态:与 DFS 类似,要保存所有的信息

3 行动:与 DFS 类似,枚举所有可能的行动

4 胜利条件/ 结束条件:题目明确地给出

5 约束

6* 判重:如何判断状态已经重复?- DFS 问题中,使用判重来减少搜索量:记忆化搜索

7* 输出方案:通过记录父亲状态,一步一步回推。 - 为什么在 DFS 问题中,我们没有着重提出如何输出方案?

 

 

好了,那么到现在为止,基础搜索题目我已经把我所学到的全部整理完了,

如果你认为还有和这些题目同样经典的,请私信找我

byebye!\(^o^)/~

posted @ 2017-05-24 17:48  DDYYZZ  阅读(681)  评论(0编辑  收藏  举报