• 深度优先搜索DFS


    一些杭电上的题目,给出代码,我具体理解的也不是很好。没有理解,就是不行啊,现在都有点忘了。

    Tempter of the Bone

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 19092    Accepted Submission(s): 5331

    Problem Description

    The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.
    The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.

    Input

    The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following:
    'X': a block of wall, which the doggie cannot enter;
    'S': the start point of the doggie;
    'D': the Door; or
    '.': an empty block.
    The input is terminated with three 0's. This test case is not to be processed.

    Output

    For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.

    Sample Input

    4 4 5

    S.X.

    ..X.

    ..XD

    ....

    3 4 5

    S.X.

    ..X.

    ...D

    0 0 0

    Sample Output

    NO

    YES

    #include <iostream>

    using namespace std;

    #include <stdio.h>

    #include <math.h>

    #include <string.h>

    #define N 10

    int dir[4][2] = {0,-1,1,0,0,1,-1,0};//define up,right,down,left index

    int escape,di,dj,T,m,n;//escape 是否逃脱,di,dj为目的地址坐标,T为恰好到达的时间,m,n为地图大小

    char map[N][N];

    void dfs(int si,int sj,int t)//t 记录现在已经走了几步

    {

        int i;

        if(si == di && sj == dj && t == T)//成功到达目的地,并且时间相等,成功逃脱

        {

            escape = 1;

            return;

        }

        if(si < 0 || si >= m || sj < 0 || sj >= n)//越界中断

            return;

        if(T-t <(abs(si-di)+abs(sj-dj)))//如果剩下要走的步 少于当前能够到达的最少步 则逃脱失败

            return;

        if(( T - t - abs(si - di) - abs(sj - dj) ) % 2 != 0)//奇偶剪枝 如果剩下要走的步 多于当前能够到达的最少步

                                                            //求差,如果不是为偶数,则无法准确到达,即逃脱失败

            return;

        for(i = 0 ; i < 4; i++)//各个方向搜索开始

        {

            if(si + dir[i][0] >= 0 && si + dir[i][0] < m && sj + dir[i][1] >= 0 && sj + dir[i][1] < n )

            {//保证每个搜索的点,都在map中

                if(map[si + dir[i][0]][sj+dir[i][1]] != 'X' )

                {

                    map[si + dir[i][0]][sj+dir[i][1]] = 'X';//将访问过的标记已访问

                    dfs(si+dir[i][0],sj+dir[i][1],t+1);//从这一点开始,继续深度优先搜索

                    if(escape) return;//如果逃脱则返回

                    map[si+dir[i][0]][sj+dir[i][1]] = '.';//回溯,赋值初始值   

                }

            }

        }

        return ;

    }

    int main()

    {

        int i,j,si,sj,t,num;

        while(scanf("%d %d %d",&m,&n,&T) != EOF)

        {

            getchar();

            if(m == 0 && n == 0 && T == 0)

                break;

            num = 0;

            for(i = 0 ; i < m ; i++)

            {

                for(j = 0 ; j < n ; j++)

                {

                    scanf("%c",&map[i][j]);

                    if(map[i][j] == 'S')

                        si = i,sj = j;

                    else if(map[i][j] == 'D')

                        di = i,dj = j;

                    else if(map[i][j] == 'X')

                        num++;

                }

                getchar();

            }

            if(m*n - num < T)//路径剪枝,如果能走的路小于时间T,则无法到达

            {

                puts("NO");

                continue;

            }

            escape = 0;

            map[si][sj] = 'X';

            dfs(si,sj,0);

            puts(escape ? "YES" : "NO" );

           

        }

    }

    Oil Deposits

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 2474    Accepted Submission(s): 1390

    Problem Description

    The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

    Input

    The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket.

    Output

    For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

    Sample Input

    1 1

    *

    3 5

    *@*@*

    **@**

    *@*@*

    1 8

    @@****@*

    5 5

    ****@

    *@@*@

    *@**@

    @@@*@

    @@**@

    0 0

    Sample Output

    0

    1

    2

    2

    #include <iostream>

    using namespace std;

    int dir[8][2] = {0,-1,1,-1,1,0,1,1,0,1,-1,1,-1,0,-1,-1};

    char map[110][110];

    int m,n;

    void dfs(int a,int b)

    {

        int i;

        for(i = 0 ; i < 8 ; i++)

        {

            if(a+dir[i][0] >= 0 && a+dir[i][0] < m && b+dir[i][1] >= 0 && b+dir[i][1] < n)

            {

                if(map[a+dir[i][0]][b+dir[i][1]] == '@')

                {

                    map[a+dir[i][0]][b+dir[i][1]] = '*';

                    dfs(a+dir[i][0],b+dir[i][1]);

                }

            }

        }

    }

    int main()

    {

        while(scanf("%d %d",&m,&n) != EOF)

        {

            int i,j;

            int cnt = 0;

            if(m == 0 || n == 0)

                break;

            for(i = 0 ; i < m;i++)

                scanf("%s",map[i]);

            for(i = 0 ; i < m;i++)

            {

                for(j = 0 ; j < n;j++)

                {

                    if(map[i][j] == '@')

                    {

                        map[i][j] = '*';

                        dfs(i,j);

                        cnt++;

                    }

                }

            }

            printf("%d\n",cnt);       

        }

    }

    Prime Ring Problem

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 7023    Accepted Submission(s): 3144

    Problem Description

    A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

    Note: the number of first circle should always be 1.

    Input

    n (0 < n < 20).

    Output

    The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.

    You are to write a program that completes above process.

    Print a blank line after each case.

    Sample Input

    6

    8

    Sample Output

    Case 1:

    1 4 3 2 5 6

    1 6 5 2 3 4

    Case 2:

    1 2 3 8 5 6 7 4

    1 2 5 8 3 4 7 6

    1 4 7 6 5 8 3 2

    1 6 7 4 3 8 5 2

    #include <iostream>

    using namespace std;

    int prim[40];

    int res[25];

    int mark[25];

    int n;

    void dfs(int t)

    {

        if(t == n+1)

        {

            if(prim[1+res[t-1]])

            {

                printf("1");

                int i;

                for(i = 2; i <= n ;i++)

                    printf(" %d",res[i]);

                printf("\n");

            }

            return;

        }

        int i;

        for(i = 2; i <= n;i++)

        {

            if(!mark[i] && prim[res[t-1]+i])

            {

                mark[i] = 1;

                res[t] = i;

                dfs(t+1);

                mark[i] = 0;

            }

        }

    }

    int main()

    {

        prim[3] = prim[5] = prim[7] = prim[11] = prim[13] = prim[17] = prim[19] = prim[23] = prim[29] = prim[31] = 1;

        memset(mark,0,sizeof(mark));

        int cnt = 0;

        while(scanf("%d",&n) != EOF)

        {

            printf("Case %d:\n",++cnt);

            mark[1] = 1;

            res[1] = 1;

            dfs(2);

            printf("\n");

        }

    }

    Zipper

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 2179    Accepted Submission(s): 779

    Problem Description

    Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.

    For example, consider forming "tcraete" from "cat" and "tree":

    String A: cat
    String B: tree
    String C: tcraete


    As you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming "catrtee" from "cat" and "tree":

    String A: cat
    String B: tree
    String C: catrtee


    Finally, notice that it is impossible to form "cttaree" from "cat" and "tree".

    Input

    The first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line.

    For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.

    Output

    For each data set, print:

    Data set n: yes

    if the third string can be formed from the first two, or

    Data set n: no

    if it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.

    Sample Input

    3

    cat tree tcraete

    cat tree catrtee

    cat tree cttaree

    Sample Output

    Data set 1: yes

    Data set 2: yes

    Data set 3: no

    《此题还有DP的做法》

    #include <iostream>

    #include <string.h>

    using namespace std;

    int n;

    int flag;

    int len1,len2,len3;

    int marka[205],markb[205];

    char a[205],b[205],c[410];

    void dfs(int i,int j, int k)

    {

        if(k == len3)

        {

            flag = 1;

            return;

        }

        if(marka[i] && markb[j] )

            return;

        if(i < len1 && a[i] == c[k]) {marka[i] = 1;dfs(i+1,j,k+1);}

        if(j < len2 && b[j] == c[k]) {markb[j] = 1;dfs(i,j+1,k+1);}

    }

    int main()

    {

        scanf("%d",&n);

        int cnt = 0;

        while(n--)

        {

            printf("Data set %d: ",++cnt);

            int i;

            scanf("%s %s %s",a,b,c);

            len1 = strlen(a);

            len2 = strlen(b);

            len3 = strlen(c);

            memset(marka,0,sizeof(marka));

            memset(markb,0,sizeof(markb));

            flag = 0;

            dfs(0,0,0);

            puts(flag ? "yes":"no");

           

        }   

    }

    变形课

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
    Total Submission(s): 3011    Accepted Submission(s): 1000

    Problem Description

    呃......变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体.
    Harry已经将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse),你知道,如果他自己不能完成的话,他就只好向Hermione请教,并且被迫听一大堆好好学习的道理.

    Input

    测试数据有多组。每组有多行,每行一个单词,仅包括小写字母,是Harry所会的所有咒语.数字0表示一组输入结束.

    Output

    如果Harry可以完成他的作业,就输出"Yes.",否则就输出"No."(不要忽略了句号)

    Sample Input

    so

    soon

    river

    goes

    them

    got

    moon

    begin

    big

    0

    #include <iostream>

    using namespace std;

    typedef struct

    {

        char begin,end;

        int flag;

    }Model;

    int n,flag;

    Model test[10000];

    void dfs(char c)

    {

        if(flag == 1)

            return;

        if(c == 'm')

        {

            flag = 1;

            return;

        }

        int i;

        for(i = 1; i < n;i++)

        {

            if(test[i].begin == c && test[i].flag == 0)

            {

                test[i].flag = 1;

                dfs(test[i].end);

                test[i].flag = 0;

            }

        }   

    }

    int main()

    {

        char s[20];

        while(scanf("%s",s) != EOF)

        {

            n = 1;

            while(strcmp(s,"0"))

            {

                test[n].begin = s[0];

                test[n].end = s[strlen(s)-1];

                test[n].flag = 0;

                n++;

                scanf("%s",s);

            }

            flag = 0;

            dfs('b');

            puts(flag ?"Yes.":"No.");

        }

    }

    Red and Black

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 1759    Accepted Submission(s): 1165

    Problem Description

    There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

    Write a program to count the number of black tiles which he can reach by repeating the moves described above.

    Input

    The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

    There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

    '.' - a black tile
    '#' - a red tile
    '@' - a man on a black tile(appears exactly once in a data set)

    Output

    For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).

    Sample Input

    6 9

    ....#.

    .....#

    ......

    ......

    ......

    ......

    ......

    #@...#

    .#..#.

    11 9

    .#.........

    .#.#######.

    .#.#.....#.

    .#.#.###.#.

    .#.#..@#.#.

    .#.#####.#.

    .#.......#.

    .#########.

    ...........

    11 6

    ..#..#..#..

    ..#..#..#..

    ..#..#..###

    ..#..#..#@.

    ..#..#..#..

    ..#..#..#..

    7 7

    ..#.#..

    ..#.#..

    ###.###

    ...@...

    ###.###

    ..#.#..

    ..#.#..

    0 0

    Sample Output

    45

    59

    6

    13

    #include <iostream>

    using namespace std;

    int m,n;

    int si,sj;

    char map[30][30];

    int cnt;

    int dir[4][2] = {0,-1,1,0,0,1,-1,0};

    int dfs(int a,int b)

    {

        int i;

        for(i = 0 ; i < 4;i++)

        {

            if(a+dir[i][0] >= 0 && a+dir[i][0] < n && b+dir[i][1] >= 0 && b+dir[i][1] < m)

            {

                if(map[a+dir[i][0]][b+dir[i][1]] == '.')

                {

                    map[a+dir[i][0]][b+dir[i][1]] = '#';

                        ++cnt;

                    dfs(a+dir[i][0],b+dir[i][1]);           

                }

            }

        }

        return cnt;

    }

    int main()

    {

        while(scanf("%d %d",&m,&n) != EOF)

        {

            getchar();

            if(m+n == 0)

                break;

            int i,j;

            for(i = 0;i < n ;i++)

            {

                for(j = 0 ; j < m;j++)

                {

                    scanf("%c",&map[i][j]);

                    if(map[i][j] == '@')

                        si = i, sj = j;

                }

                getchar();

            }

            cnt = 1;

            int ans = dfs(si,sj);

            printf("%d\n",ans);

        }

    }

  • 相关阅读:
    calendar.getTimeInMillis() 和 System.currentTimeMillis() 的区别
    微信小程序中使用 <web-view> 内嵌 H5 时,登录问题的处理方法
    小程序 TabBar 定制
    webpack 代码优化压缩方法
    react-router v4 按需加载的配置方法
    axios发送post请求,如何提交表单数据?
    react中键盘enter事件处理
    常用证件正则表达式
    react中input自动聚焦问题
    React Router v4 页面传值的三种方法
  • 原文地址:https://www.cnblogs.com/newwy/p/1893551.html
Copyright © 2020-2023  润新知