zoukankan      html  css  js  c++  java
  • 【2018.07.29】(深度优先搜索/回溯)学习DFS算法小记

    参考网站:https://blog.csdn.net/ldx19980108/article/details/76324307

    这个网站里有动态图给我们体现BFS和DFS的区别:https://www.cnblogs.com/0kk470/p/7555033.html

    这个算法还算好理解一点吧,有递归的思路,理解了一个上午~

    感觉还不错,看完代码基本上就懂了,可以自己实现了

    Fire Net

    Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall.

    A blockhouse is a small castle that has four openings through which to shoot. The four openings are facing North, East, South, and West, respectively. There will be one machine gun shooting through each opening.

    Here we assume that a bullet is so powerful that it can run across any distance and destroy a blockhouse on its way. On the other hand, a wall is so strongly built that can stop the bullets.

    The goal is to place as many blockhouses in a city as possible so that no two can destroy each other. A configuration of blockhouses is legal provided that no two blockhouses are on the same horizontal row or vertical column in a map unless there is at least one wall separating them. In this problem we will consider small square cities (at most 4x4) that contain walls through which bullets cannot run through.

    The following image shows five pictures of the same board. The first picture is the empty board, the second and third pictures show legal configurations, and the fourth and fifth pictures show illegal configurations. For this board, the maximum number of blockhouses in a legal configuration is 5; the second picture shows one way to do it, but there are several other ways.

    Your task is to write a program that, given a description of a map, calculates the maximum number of blockhouses that can be placed in the city in a legal configuration.

    The input file contains one or more map descriptions, followed by a line containing the number 0 that signals the end of the file. Each map description begins with a line containing a positive integer nthat is the size of the city; n will be at most 4. The next n lines each describe one row of the map, with a '.' indicating an open space and an uppercase 'X' indicating a wall. There are no spaces in the input file.

    For each test case, output one line containing the maximum number of blockhouses that can be placed in the city in a legal configuration.

    Sample input:

    4
    .X..
    ....
    XX..
    ....
    2
    XX
    .X
    3
    .X.
    X.X
    .X.
    3
    ...
    .XX
    .XX
    4
    ....
    ....
    ....
    ....
    0
    

    Sample output:

    5
    1
    5
    2
    4
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    /*拿到这道题目,我肯定是不会的啦,所以我去摆渡了一下具体实现方法,用到的是dfs算
    法,简单看了例题,需要用到的是遍历整个数组。按照这个思维模式的话,我觉得这道题
    也可以用递归的方法做*/
    //先测试一下输入会不会出错
    /*有地图就会有二维数据,但记录step的时候依旧要使用单个数字,这时候纵坐标X=step/
    len+1,横坐标Y=step%len+1,如果二维地图是从(1,1)开始输入的话*/
    char a[5][5]; 
    int Count,len;
    
    int judge( int x , int y)
    {
        int i;
        //判断上面有没有碉堡或者墙壁,此时的Y大小不变 
        for ( i=x-1 ; i>0 ; i-- )
        {
            if ( a[i][y] == 'O' ) return 0;//上面有堡垒了,不满足,退出函数
            if ( a[i][y] == 'X' ) break;//上面有墙壁了,满足,跳出循环 
        }
        //判断左边有没有碉堡或者墙壁,此时的X大小不变
        for ( i=y-1 ; i>0 ; i-- )
        {
            if ( a[x][i] == 'O' ) return 0;//左边有堡垒了,不满足,退出函数
            if ( a[x][i] == 'X' ) break;//左边有墙壁了,满足,跳出循环   
        } 
        return 1;//上面条件两者皆满足,该点满足条件,返回1 
    }
    
    void dfs(int step, int num )//step是当前位置,num是在这个分支下最大的count 
    {
        if ( step==len*len ) //如果发现这时候达到了上限,要开始回溯到上个岔路口 
        {
            if ( num > Count ) Count=num;//如果这种情况下碉堡比较多的话替换 
            return;
        }
        int x=step/len+1 ,y=step%len+1;//数字向二维坐标转换,这里是从(1,1)开始输入的 
        if ( a[x][y]=='.' && judge(x,y) )//如果这个点是个空地的话,且前面没碉堡的话
        {
            a[x][y]='O';//标记作用,将这个点替换成碉堡 
            dfs( step+1 , num+1 );//向着下一个点前进 
            a[x][y]='.';//变回空地,为了回溯时候可以恢复岔路口的初始状态 
        }
        dfs( step+1 , num );//不管上面的这句if条件满不满足,都要进入下一句的判断 
    }
    
    int main(void)
    {
        int i, j, count;
        while ( scanf("%d", &len) , len )
        {
            for ( i=1 ; i<=len ; i++ )
            {
                getchar();
                for ( j=1 ; j<=len ; j++ )
                {
                    scanf("%c", &a[i][j] );
                }
                //getchar(); getchar不能放这里,会导致第一个字符会是回车(刚输完数字时) 
            }
            /*输入测试for ( i=1 ; i<=len ; i++ )
            {
                for ( j=1 ; j<=len ; j++ )
                {
                    printf("%c", a[i][j] );
                }
            }*/
            Count=0;
            dfs(0,0);
            cout<<Count<<endl; 
        }
        return 0;
    }

     Image Perimeters

    Technicians in a pathology lab analyze digitized images of slides. Objects on a slide are selected for analysis by a mouse click on the object. The perimeter of the boundary of an object is one useful measure. Your task is to determine this perimeter for selected objects.

    The digitized slides will be represented by a rectangular grid of periods, '.', indicating empty space, and the capital letter 'X', indicating part of an object. Simple examples are

    An X in a grid square indicates that the entire grid square, including its boundaries, lies in some object. The X in the center of the grid below is adjacent to the X in any of the 8 positions around it. The grid squares for any two adjacent X's overlap on an edge or corner, so they are connected.

    XXX
    XXX Central X and adjacent X's
    XXX

    An object consists of the grid squares of all X's that can be linked to one another through a sequence of adjacent X's. In Grid 1, the whole grid is filled by one object. In Grid 2 there are two objects. One object contains only the lower left grid square. The remaining X's belong to the other object.

    The technician will always click on an X, selecting the object containing that X. The coordinates of the click are recorded. Rows and columns are numbered starting from 1 in the upper left hand corner. The technician could select the object in Grid 1 by clicking on row 2 and column 2. The larger object in Grid 2 could be selected by clicking on row 2, column 3. The click could not be on row 4, column 3.


    One useful statistic is the perimeter of the object. Assume each X corresponds to a square one unit on each side. Hence the object in Grid 1 has perimeter 8 (2 on each of four sides). The perimeter for the larger object in Grid 2 is illustrated in the figure at the left. The length is 18.

    Objects will not contain any totally enclosed holes, so the leftmost grid patterns shown below could NOT appear. The variations on the right could appear:

    The input will contain one or more grids. Each grid is preceded by a line containing the number of rows and columns in the grid and the row and column of the mouse click. All numbers are in the range 1-20. The rows of the grid follow, starting on the next line, consisting of '.' and 'X' characters.

    The end of the input is indicated by a line containing four zeros. The numbers on any one line are separated by blanks. The grid rows contain no blanks.

    For each grid in the input, the output contains a single line with the perimeter of the specified object.


    Example input:

    2 2 2 2
    XX
    XX
    6 4 2 3
    .XXX
    .XXX
    .XXX
    ...X
    ..X.
    X...
    5 6 1 3
    .XXXX.
    X....X
    ..XX.X
    .X...X
    ..XXX.
    7 7 2 6
    XXXXXXX
    XX...XX
    X..X..X
    X..X...
    X..X..X
    X.....X
    XXXXXXX
    7 7 4 4
    XXXXXXX
    XX...XX
    X..X..X
    X..X...
    X..X..X
    X.....X
    XXXXXXX
    0 0 0 0


    Example output:

    8
    18
    40
    48
    8

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    /*这道题我想用dfs的方法去做,但是step不能像上一题那样是已经确定好了的,所以边界
    条件很好找,这道题的边界条件是没有下一个点了,每增加一个点会增加4的周长,再判断
    它是不是孤独的一个点,但这就会带来很多问题,因为相邻的方块会削减周长,削减一个边
    还是很好计算的,面对这种可能每个边都会接触的情况,我确实没什么想法= =如果是从头
    开始计算的,会一直不停往右和下发展,那么我只要每次判断左上就行了,这么一说我就有
    想法了,我往左上和右下分开发展,分开判断就行了(但是这样代码量也太多了= =),我
    还是去百度看下别人的看法吧*/ 
    /*有想法了,就靠'x'和'.'之间的互相转化,count出一共有多少个方块就行,但是这样算
    不出其周长呀= =真是困扰,斜对角的方块不会削减,临边的方块削减1*/
    /*突然又有想法了,如果我的DFS从左上角向右下角发展的话*/
    /*貌似百度到的他的想法和我的不太一样呢O.O*/ 
    char a[51][51];
    int sign[51][51];
    int dirx[8]={0,0,1,-1,1,-1,1,-1};
    int diry[8]={1,-1,0,0,1,-1,-1,1};
    int hang, lie, shang, slie, Count, xx, yy;
    
    void dfs(int x, int y)
    {
        Count+=4;//因为这个点是X,边长为4
        sign[x][y]=1;//这个点做过判断了,做好标记
        for(int i=0;i<8;i++)
         {
            xx=x+dirx[i];
            yy=y+diry[i];
            if ( 1<=xx && xx<=hang && 1<=yy && yy<=lie && a[xx][yy]=='X' )
            {
                 if( sign[xx][yy]==0)   dfs(xx,yy);
                 //如果这个点没受过判断的话,进入下一个点的dfs 
                 if( dirx[i]*diry[i]==0 )  Count--;
                 //不在斜上方或斜下方就需要减去从边。
            }   
        }
    }
    
    int main(void)
    {
        int i, j;
        while ( scanf("%d%d%d%d", &hang, &lie, &shang, &slie) , (hang||lie||shang||slie))
        {
            for ( i=1 ; i<=hang ; i++ )
            {
                getchar();
                for ( j=1 ; j<=lie ; j++ )
                {
                    scanf("%c", &a[i][j]);
                }
            }
            Count=0;
            memset( sign , 0 , sizeof(sign) );//将sign中的所有数据清零 
            if ( a[shang][slie]=='X' ) dfs(shang,slie);
            printf("%d
    ",Count);
        } 
        return 0;
    }

    Prime Ring Problem

    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. 

     

    Inputn (0 < n < 20). 
    OutputThe 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 <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    /*这题我猜测使用dfs的方法,既然第一个数字一定会是1,那么就可以从1开始慢慢递增,
    一步步递归*/
    /*还有一个没有考虑的,就是这个数字有没有被用过*/
    /*犯了一个很有趣的错误,就是我在函数外定义了linshi作为循环的条件,但是这样做带来
    的后果就是每次递归这个函数时候无论是标记还是做其他事情,使用的都是外面的空间,对
    递归本身带来了影响,应该重新在函数内开辟空间作为临时数据的存储空间*/
    int a[21], len, allcount=1;
    bool b[21],sign; 
    
    int judge( int a, int b)
    {
        int c=a+b;
        switch (c)
        {
            case 2:
            case 3:
            case 5:
            case 7:
            case 11:
            case 13:
            case 17:
            case 19:
            case 23:
            case 29:
            case 31:
            case 37:
                return true;
            default:
                return false;
        }
    }
    
    void dfs(int step)
    {
        if ( step==len && judge(a[1], a[len]) )//达到最后一步,打印出这个数组吧 
        { 
            printf("1");
            for ( int i=2 ; i<=len ; i++ )
            {
                printf(" %d", a[i]);
            }
            printf("
    ");
        }
        int linshi;
        for ( linshi=2 ; linshi<=len ; linshi++ )
        {
            if ( !b[linshi] && judge( a[step] , linshi ))
            {
                b[linshi]=true;//标记这个点,我要开始用这个点了哦
                a[step+1]=linshi; 
                dfs(step+1);
                b[linshi]=false;//恢复这个标记,这个点就当我没用过
            }
        }
    }
     
    int main(void)
    {
        while ( scanf("%d", &len)!=EOF )
        {
            cout<<"Case "<<allcount++<<":"<<endl;
            memset( b , false , sizeof(b) );//重置判断是否使用过的标记数组 
            a[1]=1;
            b[1]=true;
            dfs(1);
            cout<<endl;
        }
        return 0;
    }

    Lake Counting

    Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. 
    Given a diagram of Farmer John's field, determine how many ponds he has.

    Input

    * Line 1: Two space-separated integers: N and M 
    * Lines 2..N+1: M characters per line representing one row of Farmer John's field. Each character is either 'W' or '.'. The characters do not have spaces between them.

    Output

    * Line 1: The number of ponds in Farmer John's field.

    Sample Input

    10 12
    W........WW.
    .WWW.....WWW
    ....WW...WW.
    .........WW.
    .........W..
    ..W......W..
    .W.W.....WW.
    W.W.W.....W.
    .W.W......W.
    ..W.......W.

    Sample Output

    3

    Hint

    OUTPUT DETAILS: 

    There are three ponds: one in the upper left, one in the lower left,and one along the right side.
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    /*看到这道题我的想法也是dfs,但是dfs会不会用得有点多了呢,我好像在网上看到过另外
    一种算法,去看看吧。  果然还是dfs算法呢*/
    /*昨天那道题给了我很多想法,他有立两个数组来代替八个方向,我感觉非常好,我这次使
    用dfs可以试着温习一下昨天的这个数组代表方向的方法*/
    /*我刚才又没考虑到该点会重复使用的情况,看了昨天的代码让我恍然大悟,我还需要一个
    bool数组来记录我的情况*/
    /*总体的代码打出来了,但是有个难点就是怎样才能知道进行到最后一步呢?这么想的时候
    我的脑海中冒出了一个想法,第一个检索点就是固定有的第一个点,我可以不用判断最后一
    步,转而判断第一步才对*/
    /*然后又发现自己一个错误,这样子的算法我只是从(1,1)点开始统计有多少个相邻的W罢了
    ,而不是遍历整个地图去找到所有点。发现了自己这个错误我又有想法了*/
    int hang, lie, Count=0;
    char a[101][101];
    bool b[101][101]; 
    int shang[8]={-1,-1,-1, 0, 0, 1, 1, 1};
    int slie[8]= {-1, 0, 1,-1, 1,-1, 0, 1};
    //上面这两句代表着从左上到右下 
    
    void dfs(int x, int y)
    {
        if ( x<1 || x>hang || y<1 || y>lie ) return;
        //首先欢迎新来的成员~,判断新成员有咩有越界呀。越界了,告辞!
        b[x][y]=true;//被安排上了 
        int i, xx, yy;//这次总算记得了,回溯的参数不能在外定义  
        for ( i=0 ; i<8 ; i++ )
        {
            xx=x+shang[i];
            yy=y+slie[i];
            if ( a[xx][yy]=='W' && xx>0 && xx<=hang && yy>0 && yy<=lie )
            {
                if ( b[xx][yy]==false ) dfs( xx , yy );
            }
        }
    }
    
    int main(void)
    {
        memset( b, false , sizeof(b));
        scanf("%d%d", &hang ,&lie );
        getchar();
        for ( int i=1 ; i<=hang ; i++ )
        {
            for ( int j=1 ; j<=lie ; j++ )
            {
                scanf("%c", &a[i][j]);//检查了老半天原来是忘记加&了(捂脸 
            }
            getchar();
        }
        //dfs(1,1);//果然我还是喜欢从(1,1)开始输入呢~(=v=)y
        //上面这句话的想法是错误的,只有从第一个点开始做,而不是遍历整个地图
        for ( int i=1 ; i<=hang ; i++ )
        {
            for ( int j=1 ; j<=lie ; j++ )
            {
                if ( a[i][j]=='.' ) continue;
                if ( a[i][j]=='W' && b[i][j]==false )
                {
                    dfs(i,j);
                    Count++;
                } 
            }
        }
        printf("%d
    ",Count);
        return 0;
    }

    棋盘问题

    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

    Input

    输入含有多组测试数据。 
    每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 
    当为-1 -1时表示输入结束。 
    随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。 

    Output

    对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

    Sample Input

    2 1
    #.
    .#
    4 4
    ...#
    ..#.
    .#..
    #...
    -1 -1
    

    Sample Output

    2
    1
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    //棋盘问题,这题和昨天的那道碉堡题目差不多
    /*这题让我想起了一道经典的数学题叫做八皇后*/ 
    /*但是这道题有个地方,和碉堡那题有那么一点点不一样,就是它可以放任意个棋子,感觉
    这道题才真的是时间复杂度为!n的算法(如果使用DFS的话)*/
    /*我的想法和百度的不太一样,所以我才会想到时间复杂读会那么高,百度上的方法和我的
    不太一样,他将其分为很多行,只要这行输入完了就可以直接跳下一行了(而我还傻傻地进
    行下一格的判断,不得不说他的想法真的很好,还建立一个列的数组来记录),只要横过去
    比较就可以知道这一列有没有棋子了*/
    using namespace std;
    char a[10][10];
    bool sign[10];        //记录一列是否已经放过棋子
    int n,k;
    int allcount,m;
    
    void DFS(int cur)
    {
        if(k==m)
        {
            allcount++;
            return;
        }
        if(cur>n)    return;
        for(int j=1; j<=n; j++)
        {
            if(sign[j]==false && a[cur][j]=='#')  //判断条件
            {
                sign[j]=true;//安排上了 
                m++;                 
                DFS(cur+1);
                sign[j]=false; 
                m--;
            }
        }
        DFS(cur+1); //到下一行
    }
    
    int main()
    {
        int i,j;
        while( scanf("%d%d",&n,&k) )
        {
            if ( n==-1 && k==-1 ) break;
            allcount=0;
            m=0;
            getchar();
            for(i=1; i<=n; i++)
            {
                for ( j=1 ; j<=n ; j++ )
                {
                    scanf("%c",&a[i][j]);
                }
                getchar();
            }    
            memset(sign, false ,sizeof(sign));
            DFS(1);
            printf("%d
    ",allcount);
        }
        return 0;
    }

    哈密顿绕行世界问题

    一个规则的实心十二面体,它的 20个顶点标出世界著名的20个城市,你从一个城市出发经过每个城市刚好一次后回到出发的城市。 

    Input前20行的第i行有3个数,表示与第i个城市相邻的3个城市.第20行以后每行有1个数m,m<=20,m>=1.m=0退出. 
    Output输出从第m个城市出发经过每个城市1次又回到m的所有路线,如有多条路线,按字典序输出,每行1条路线.每行首先输出是第几条路线.然后个一个: 后列出经过的城市.参看Sample output 
    Sample Input

    2 5 20
    1 3 12
    2 4 10
    3 5 8
    1 4 6
    5 7 19
    6 8 17
    4 7 9
    8 10 16
    3 9 11
    10 12 15
    2 11 13
    12 14 20
    13 15 18
    11 14 16
    9 15 17
    7 16 18
    14 17 19
    6 18 20
    1 13 19
    5
    0

    Sample Output

    1:  5 1 2 3 4 8 7 17 18 14 15 16 9 10 11 12 13 20 19 6 5
    2:  5 1 2 3 4 8 9 10 11 12 13 20 19 18 14 15 16 17 7 6 5
    3:  5 1 2 3 10 9 16 17 18 14 15 11 12 13 20 19 6 7 8 4 5
    4:  5 1 2 3 10 11 12 13 20 19 6 7 17 18 14 15 16 9 8 4 5
    5:  5 1 2 12 11 10 3 4 8 9 16 15 14 13 20 19 18 17 7 6 5
    6:  5 1 2 12 11 15 14 13 20 19 18 17 16 9 10 3 4 8 7 6 5
    7:  5 1 2 12 11 15 16 9 10 3 4 8 7 17 18 14 13 20 19 6 5
    8:  5 1 2 12 11 15 16 17 18 14 13 20 19 6 7 8 9 10 3 4 5
    9:  5 1 2 12 13 20 19 6 7 8 9 16 17 18 14 15 11 10 3 4 5
    10:  5 1 2 12 13 20 19 18 14 15 11 10 3 4 8 9 16 17 7 6 5
    11:  5 1 20 13 12 2 3 4 8 7 17 16 9 10 11 15 14 18 19 6 5
    12:  5 1 20 13 12 2 3 10 11 15 14 18 19 6 7 17 16 9 8 4 5
    13:  5 1 20 13 14 15 11 12 2 3 10 9 16 17 18 19 6 7 8 4 5
    14:  5 1 20 13 14 15 16 9 10 11 12 2 3 4 8 7 17 18 19 6 5
    15:  5 1 20 13 14 15 16 17 18 19 6 7 8 9 10 11 12 2 3 4 5
    16:  5 1 20 13 14 18 19 6 7 17 16 15 11 12 2 3 10 9 8 4 5
    17:  5 1 20 19 6 7 8 9 10 11 15 16 17 18 14 13 12 2 3 4 5
    18:  5 1 20 19 6 7 17 18 14 13 12 2 3 10 11 15 16 9 8 4 5
    19:  5 1 20 19 18 14 13 12 2 3 4 8 9 10 11 15 16 17 7 6 5
    20:  5 1 20 19 18 17 16 9 10 11 15 14 13 12 2 3 4 8 7 6 5
    21:  5 4 3 2 1 20 13 12 11 10 9 8 7 17 16 15 14 18 19 6 5
    22:  5 4 3 2 1 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5
    23:  5 4 3 2 12 11 10 9 8 7 6 19 18 17 16 15 14 13 20 1 5
    24:  5 4 3 2 12 13 14 18 17 16 15 11 10 9 8 7 6 19 20 1 5
    25:  5 4 3 10 9 8 7 6 19 20 13 14 18 17 16 15 11 12 2 1 5
    26:  5 4 3 10 9 8 7 17 16 15 11 12 2 1 20 13 14 18 19 6 5
    27:  5 4 3 10 11 12 2 1 20 13 14 15 16 9 8 7 17 18 19 6 5
    28:  5 4 3 10 11 15 14 13 12 2 1 20 19 18 17 16 9 8 7 6 5
    29:  5 4 3 10 11 15 14 18 17 16 9 8 7 6 19 20 13 12 2 1 5
    30:  5 4 3 10 11 15 16 9 8 7 17 18 14 13 12 2 1 20 19 6 5
    31:  5 4 8 7 6 19 18 17 16 9 10 3 2 12 11 15 14 13 20 1 5
    32:  5 4 8 7 6 19 20 13 12 11 15 14 18 17 16 9 10 3 2 1 5
    33:  5 4 8 7 17 16 9 10 3 2 1 20 13 12 11 15 14 18 19 6 5
    34:  5 4 8 7 17 18 14 13 12 11 15 16 9 10 3 2 1 20 19 6 5
    35:  5 4 8 9 10 3 2 1 20 19 18 14 13 12 11 15 16 17 7 6 5
    36:  5 4 8 9 10 3 2 12 11 15 16 17 7 6 19 18 14 13 20 1 5
    37:  5 4 8 9 16 15 11 10 3 2 12 13 14 18 17 7 6 19 20 1 5
    38:  5 4 8 9 16 15 14 13 12 11 10 3 2 1 20 19 18 17 7 6 5
    39:  5 4 8 9 16 15 14 18 17 7 6 19 20 13 12 11 10 3 2 1 5
    40:  5 4 8 9 16 17 7 6 19 18 14 15 11 10 3 2 12 13 20 1 5
    41:  5 6 7 8 4 3 2 12 13 14 15 11 10 9 16 17 18 19 20 1 5
    42:  5 6 7 8 4 3 10 9 16 17 18 19 20 13 14 15 11 12 2 1 5
    43:  5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5
    44:  5 6 7 8 9 16 17 18 19 20 1 2 12 13 14 15 11 10 3 4 5
    45:  5 6 7 17 16 9 8 4 3 10 11 15 14 18 19 20 13 12 2 1 5
    46:  5 6 7 17 16 15 11 10 9 8 4 3 2 12 13 14 18 19 20 1 5
    47:  5 6 7 17 16 15 11 12 13 14 18 19 20 1 2 3 10 9 8 4 5
    48:  5 6 7 17 16 15 14 18 19 20 13 12 11 10 9 8 4 3 2 1 5
    49:  5 6 7 17 18 19 20 1 2 3 10 11 12 13 14 15 16 9 8 4 5
    50:  5 6 7 17 18 19 20 13 14 15 16 9 8 4 3 10 11 12 2 1 5
    51:  5 6 19 18 14 13 20 1 2 12 11 15 16 17 7 8 9 10 3 4 5
    52:  5 6 19 18 14 15 11 10 9 16 17 7 8 4 3 2 12 13 20 1 5
    53:  5 6 19 18 14 15 11 12 13 20 1 2 3 10 9 16 17 7 8 4 5
    54:  5 6 19 18 14 15 16 17 7 8 9 10 11 12 13 20 1 2 3 4 5
    55:  5 6 19 18 17 7 8 4 3 2 12 11 10 9 16 15 14 13 20 1 5
    56:  5 6 19 18 17 7 8 9 16 15 14 13 20 1 2 12 11 10 3 4 5
    57:  5 6 19 20 1 2 3 10 9 16 15 11 12 13 14 18 17 7 8 4 5
    58:  5 6 19 20 1 2 12 13 14 18 17 7 8 9 16 15 11 10 3 4 5
    59:  5 6 19 20 13 12 11 10 9 16 15 14 18 17 7 8 4 3 2 1 5
    60:  5 6 19 20 13 14 18 17 7 8 4 3 10 9 16 15 11 12 2 1 5
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <stack>
    #include <queue> 
    using namespace std;
    /*看到这道题直接就懵了呀,这么多数据竟然只要一秒钟的运行时间= =这着实有点让我这
    个萌新瑟瑟发抖呢,不过既然是这种题目,第一个反应就是DFS,但是因为步数是相同的所
    以BFS也未尝不可呀。先考虑使用DFS吧~*/
    /*考虑这道题的时候我想到底是应该使用结构体还是应该使用数组呢,仔细想想数组有sort
    函数,那就使用数组吧*/
    /*但是又不得不考虑输出的问题,如果我找到最后一个点,那会变成倒序输出的*/
    /*解决办法是再创建一个数组来记录*/
    /*每次算出来都有162种,我也是醉了,不知道到底哪里错了*/
    /*终于找到了,我嘞个去,最后一步要能返回第一个点,这个BUG我找了好久阿= =真是浪费
    了我好多时间,多看几次题目就好了的= =*/
    int neighbor[21][4], footmark[21], allcount;
    bool sign[21];
    
    void dfs(int step, int n)
    {
        int linshi,temp;
        if ( step==20 )//遍历到最后一步,输出所有足迹 
        {
            if (neighbor[n][1]==footmark[1] || neighbor[n][2]==footmark[1] || neighbor[n][3]==footmark[1])
            {
                printf("%d:  ", allcount);
                for ( int i=1 ; i<=20 ; i++ )
                {
                    printf("%d ", footmark[i] );
                }
                printf("%d
    ",footmark[1]);
                allcount++; 
            }
        }
        else
        {
            for ( linshi=1 ; linshi<4 ; linshi++ )
            {
                temp=neighbor[n][linshi];
                if ( sign[temp] == false )//这个点没使用过哦,可以试一试
                {
                    step++;
                    footmark[step] = temp;
                    sign[ temp ] = true;
                    //
                    dfs( step , temp );
                    //
                    sign[ temp ] = false;
                    step--;
                }
            }
            return;
        }
    }
    
    int main(void)
    {
        int i, j, n;
        for ( i=1 ; i<=20 ; i++ )
        {
            for ( j=1 ; j<=3 ; j++ )
            {
                scanf("%d",&neighbor[i][j]); 
            }
            //sort(neighbor[i], neighbor[i]+4);
        }
        while ( scanf("%d" ,&n), n )
        {
            allcount=1;
            memset( footmark , 0 , sizeof(footmark) );
            memset( sign , false , sizeof(sign) );
            sign[n]=true;
            footmark[1]=n;
            dfs(1,n); 
        }
        return 0;
    }
  • 相关阅读:
    asp.net运行网页时出现目录清单
    c#变量命名规范
    asp.net的优点
    为什么使用javascript脚本语言以及javascript的特点组成
    ASP.NET控件
    sql2000的常见操作
    最常用的sql语句
    sql提升
    c语言学习(二) 程序的灵魂
    c语言学习(三) 数据类型
  • 原文地址:https://www.cnblogs.com/mokou/p/9385040.html
Copyright © 2011-2022 走看看