DFS · 素数环(HDU_1016)

DFS简析:

DFS(深度优先搜索) ,搜索方法是从起点开始,从某一方向一层一层往下找,直到最底层,

进行操作之后然后返回上一层换一个方向继续寻找,寻找方法有点类似根树遍历方法的前序遍历,一支一支找完之后,就完成了遍历

搜索。

实现这个算法很简单,其“本体”就是一个递归函数,如果某一方向的子支还不是最底层且满足题给条件,那么就继续调用它本身,

直到不满足递归条件(及达到最底层或不满足继续循环的条件),那么操作后进行返回,让其开始下一个方向的寻找。

不得不提到的是剪枝,DFS算法很容易超时,所以剪枝问题就是重中之重,不仅有题上所给的限定条件,一般还会有一系列的隐形条件,

但剪枝方法因题而异,此处也不方便细说。

下面看例题:(HDU_1016)

素数环问题,即给定一个数n,能不能将从1开始到n(n<=20)结束的n个数排列呈环状,并且使相邻的两个数之和为素数

输入有很多样例,每一个样例一个数n,且输入以0结尾,

对于每一个数n,首先输出"Case x:",x为当前样例个数,若存在这样的环,则从1开始依次输出,若不存在则输出"no answer"

且每一个样例后都要输出一个空行。

怎么解决这个问题呢?

我首先用埃氏筛法得到一个长为四十的数表,若下标数为素数,则存入1,否则存入0,

其次用DFS搜索,如果能将这n个数全部按要求排列起来,那么就输出这个排列,

而其间有一个小小的剪枝,若输入一个奇数,且排成环,那么这个环中肯定会有两个奇数相邻,

而这两个奇数不可能都为1,所以他们的和一定为合数,所以直接输出"no answer"就好了

代码:

#include <iostream>
#include <cstring>

using namespace std;

int a[25];//存放排好的数
int b[40];//判断下标是否为素数的数表
int visited[25];//记录点是否被走过
int n;
int flag = 0;//记录是否存在素数环
void dfs( int m, int ans )
{
    a[ans] = m;
    visited[m] = 1;
    if( ans == n-1 )
    {
        if( b[m+1] )
        {
            for( int i(0); i < n; i++ )
            {
                if( i == 0 )
                {cout << a[i];continue;}
                cout << " " << a[i];
            }
            cout << endl;
            flag++;
        }
    }
    else
    {
        for( int i = 1; i <= n; i++ )
        {
            if( b[i+m] && !visited[i] )
                dfs( i, ans+1 );
        }
    }
    visited[m] = 0;
}
main()
{
    int t = 0;
    memset( b, 1 ,sizeof(b) );//埃氏筛法
    b[0] = 0; b[1] = 0;
    for( int i(0); i*i <= 40; i++ )
        if ( b[i] )
            for( int j = 2*i; j <= 40; j += i )
                b[j] = 0;
    while( cin >> n )//输入
    {
        if( !n )
            break;
        if( n%2 == 1 )//剪枝
        {
            cout << "Case " << ++t << ":
";
            cout << "no answer" << endl << endl;
        }
        memset( a, 0, sizeof(a) );
        memset( visited, 0, sizeof(visited) );
        cout << "Case " << ++t << ":
";
        dfs( 1, 0 );
        cout << endl;
        if( !flag )//若flag仍为0,说明名优任何的环形成,所以no answer
        {
            cout << "Case " << ++t << ":
";
            cout << "no answer" << endl << endl;
        }
    }
}
原文地址:https://www.cnblogs.com/xujunming/p/6715532.html