Fork me on GitHub

 深搜(入门篇)
分类: 回溯 2011-02-17 10:15 400人阅读 评论(0) 收藏 举报
学习深搜有一些时间了,个人感觉深搜满足一定的形式:
[cpp] view plaincopy
void dfs (int a,……)     //参数个数不确定  
{  
    if (……)     //边界条件  
    {  
        ……        
    }  
    else  
    {  
        dfs(a+1,……);          
    }  
}  

若是再具体一些的话:
[cpp] view plaincopy
void dfs (int a,……)       
{  
    if (……)     //边界条件  
    {  
        ……        
    }  
    else  
    {  
        for ()      //横向遍历解答树  
        {  
            dfs(a+1,……)  
        }  
    }  
}  

 
解答树的模型、边界条件的判断和剪枝技巧是很重要的;
 
先来几个经典实例:
 
1.整数拆分:
例如:
3 = 1 + 1 + 13 = 1 + 23 = 3;
 
[cpp] view plaincopy
#include <iostream>  
#include <cstdio>  
using namespace std;  
#define MAX 30  
int res[MAX],   //保存结果  
N,  
count;          //记录结果总数  
  
void print(int cur)     //打印结果  
{  
    printf("No %-3d: %d=",count,res[0]);  
    for (int i=1; i<cur; ++i)       //结果范围是[1,cur-1]  
    {  
        printf("%3d",res[i]);  
    }  
    printf("/n");  
}  
  
void split(int cur, int remain)  
{  
    int k;      //剪枝用,可以避免重复情况  
  
    if (remain == 0)    //若剩余数值为0,拆分完毕  
    {  
        ++count;  
        print(cur);  
    }  
    else  
    {  
        k = res[cur-1];  
        if (k > remain)  
        {  
            k = remain;  
        }  
  
        for (int i=1; i<=k; ++i)  
        {  
            res[cur] = i;  
            split(cur+1,remain-i);  
        }  
    }  
}  
  
int main()  
{  
    while (scanf("%d",&N) != EOF)  
    {  
        count = 0;  
        res[0] = N;  
        split(1,N);  
    }  
    return 0;  
}  
 
 
2.组合问题:
传送门: http://blog.csdn.net/dpdldh/archive/2011/02/17/6190723.aspx
 
3.N的全排列:
 
[cpp] view plaincopy
#include <iostream>  
#include <cstdio>  
#include <cstring>  
using namespace std;  
#define MAX 30  
int res[MAX],       //存放排列数  
vis[MAX],       //标记数字是否被访问  
N,              //从1~N中排列  
count;              //情况总数  
  
void print()  
{  
    printf("No %-3d: %3d",count++,res[1]);  
    for (int i=2; i<=N; ++i)  
    {  
        printf("%3d",res[i]);  
    }  
    printf("/n");  
}  
  
void permutation(int cur)  
{  
    if (cur > N)  
    {  
        print();  
    }  
    else  
    {  
        for (int i=1; i<=N; ++i)  
        {  
            if (!vis[i])  
            {  
                vis[i] = 1;  
                res[cur] = i;  
                permutation(cur+1);  
  
                vis[i] = 0;         //这一步不要忘了!!  
            }  
        }  
    }  
}  
  
int main()  
{  
    while (scanf("%d",&N) != EOF)  
    {  
        count = 0;  
        memset(vis,0,sizeof(vis));  
        permutation(1);  
    }  
    return 0;  
}  

 
4.N皇后
传送门:http://blog.csdn.net/dpdldh/archive/2011/02/16/6188561.aspx
 
 
以上是一些经典的问题,下面来一些简单的题目:
1.TOJ 1002    (全排列问题)
http://blog.csdn.net/dpdldh/archive/2011/02/17/6190887.aspx
2.TOJ 1017    (石子归并)
http://blog.csdn.net/dpdldh/archive/2011/02/17/6190891.aspx
3.HDU 1016   (素数环)
http://blog.csdn.net/dpdldh/archive/2011/02/11/6178456.aspx

 

posted on 2013-02-04 16:46  huashiyiqike  阅读(291)  评论(0编辑  收藏  举报