Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2788601
  • 博文数量: 471
  • 博客积分: 7081
  • 博客等级: 少将
  • 技术积分: 5369
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-04 21:55
文章分类

全部博文(471)

文章存档

2014年(90)

2013年(69)

2012年(312)

分类: C/C++

2012-09-01 10:51:08


回溯法(Backtracking Algorithm)有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。 
程序实现4要点:
1、表示寻找到可行解如(m==n)
2、返回
     返回只有2种情况,找到可行解 or 不满足条件(这是程序要实现的关键点)
     如何实现返回,visit[]数组,出栈和压栈
3、这些结点是怎样扩展的,多数利用循环
4、这些解是怎样保存的,题目要求可行解的个数还是最优解


看一下N皇后问题:
题目大意:在一个n*n的棋盘上放置n个皇后棋子。皇后可以向行,列,对角线攻击。求皇后互不攻击的摆法有多少种。

点击(此处)折叠或打开

  1. /*****************************EightQueen.c***************************/

  2. #include

  3. /*

  4.  * NOTE: 该程序是一个解N皇后棋局问题的算法(采用递归解决)

  5.  * 编译环境 VC++ 6

  6.  */

  7. /* 程序随N值的改变,从而来解决N皇后问题 */

  8. #define N 4

  9. int solution[N], sols;

  10. /* 放置皇后到位置(row,col)(row,solution),若成功返回1,失败返回0 */

  11. int place(int row)
  12. {
  13.     int j;
  14.     for (j = 0; j < row; j++) /* j
  15.     {//两个对角线
  16.       if( row - solution[row] == j - solution[j] ||
  17.           row + solution[row] == j + solution[j] ||
  18.           solution[j] == solution[row] )//同一列
  19.        return 0;
  20.     }
  21.     return 1;
  22. }

  23. /* row代表开始轮到放第 row 行了,前 row-1 行都已放好 */
  24. void backtrack(int row)
  25. {
  26.     int k;//不会有N+1
  27.     if ( N == row )
  28.     {
  29.         sols++; // 解的结果加1
  30.         /* 循环打印八皇后棋局(下标转换成从1开始) */
  31.         for( k=0 ; k
  32.             printf("(%d,%d) ", solution[k]+1,k+1);
  33.         printf("\n");
  34.     }
  35.     else
  36.     {
  37.         int i;
  38.         for( i=0 ; i
  39.         {
  40.             solution[row] = i;//在这一行中j循环, solution[row]的值为j,靠!!这样来扩展结点
  41.             if( place(row) )//提前结束条件
  42.              backtrack(row + 1);
  43.         }
  44.     }
  45. }



  46. void queens()
  47. {
  48.     backtrack(0);
  49. }

  50. int main(void)
  51. {
  52.     queens();
  53.     printf("Total Solutions: %d\n", sols);
  54.     return 0;
  55. }

  56. /*
  57. (2,1) (4,2) (1,3) (3,4)
  58. (3,1) (1,2) (4,3) (2,4)
  59. Total Solutions: 2
  60. Press any key to continue
  61. */

再看一道

编程求解,输入两个整数n和m,从数列1,2,3,……n中随意取几个数,使其和等于m。要求将所有的可能组合列出来。每个数都有两种选择,加入与不加入 实际上就是一个背包问题。

求解思路:

1.首先判断,如果n>m,则n中大于m的数不可能参与组合,此时置n = m;

2.将最大数n加入且n == m,则满足条件,输出;

3.将n分两种情况求解,(1)n没有加入,取n = n - 1; m = m;递归下去;(2)n加入,取n = n - 1l, m = m - n,递归下去


点击(此处)折叠或打开

  1. #include
  2. #include
  3. using namespace std;
  4.   
  5. listlist1;//相当于栈,不过出入比栈效率高
  6. void find_factor(int sum, int n)
  7. {
  8.     // 递归出口
  9.     if(n <= 0 || sum <= 0)
  10.         return;
  11.       
  12.     // 输出找到的结果
  13.     if(sum == n)
  14.     {
  15.         for(list::iterator iter = list1.begin(); iter != list1.end(); iter++)
  16.             cout << *iter << " + ";
  17.         cout << n << endl;//n不在栈里面的,这里的实现有点技巧     
  18.     }
  19.       
  20.     list1.push_front(n); //还没找到,所以要进栈,典型的01背包问题,每个数都可以放或者不放
  21.     find_factor(sum-n, n-1); //放n,n-1个数填满sum-n
  22.     list1.pop_front();
  23.     find_factor(sum, n-1); //不放n,n-1个数填满sum
  24. }
  25.   
  26. int main()
  27. {
  28.     int sum, n;
  29.     cout << "请输入你要等于多少的数值sum:" << endl;
  30.     cin >> sum;
  31.     cout << "请输入你要从1.....n数列中取值的n:" << endl;
  32.     cin >> n;
  33.     cout << "所有可能的序列,如下:" << endl;
  34.     find_factor(sum,n);
  35.     return 0;
  36. }

  37. /*
  38. 请输入你要等于多少的数值sum:
  39. 10
  40. 请输入你要从1.....n数列中取值的n:
  41. 6
  42. 所有可能的序列,如下:
  43. 6 + 4
  44. 3 + 6 + 1
  45. 4 + 5 + 1
  46. 3 + 5 + 2
  47. 2 + 3 + 4 + 1
  48. Press any key to continue
  49. */

回溯法求01背包问题, 
【概要设计】

01背包问题是一个子集选取问题,适合于用子集树表示01背包问题的解空间。在搜索解空间树是,只要其左儿子节点是一个可行结点,搜索就进入左子树,在右子树中有可能包含最优解是才进入右子树搜索。否则将右子树剪去。

点击(此处)折叠或打开

  1. #include
  2. #include
  3.  
  4. int n=5,c=10;
  5. int value[5]={6,3,5,4,6};
  6. int weight[5]={2,2,6,5,4};
  7. int cv[5]={0,0,0,0,0};
  8. int bv[5]={0,0,0,0,0};
  9. int cw=0;
  10. int curv = 0 ;
  11. int bestv =0 ;
  12. void output()
  13. {
  14.    int i =0;
  15.    for(i; i
  16.      printf("%d ",bv[i]);
  17.    printf("%d",bestv);
  18. }
  19.  
  20. void trackback(int i)
  21. {
  22.      int j;
  23.      //递归出口,反正一定要执行到最后
  24.     if(i>=n)
  25.     {
  26.          if(bestv
  27.         {
  28.             for(j=0;j
  29.                 bv[j] = cv[j];
  30.             bestv = curv;
  31.         }
  32.     }
  33.     else
  34.     {
  35.          if(cw + weight[i]<=c)
  36.          {
  37.          cv[i] = 1;
  38.          cw +=weight[i];
  39.          curv+= value[i];
  40.          trackback(i+1);
  41.          //就算是符合条件,也要算上不加入的情况
  42.          cw -=weight[i];
  43.          curv-= value[i];
  44.          cv[i] =0;
  45.          trackback(i+1);
  46.          }
  47.          //不符合条件
  48.          else
  49.          {
  50.             cv[i] =0;
  51.             trackback(i+1);
  52.          }
  53.  
  54.     }
  55.  
  56.  
  57. }
  58. int main(int argc, char *argv[])
  59. {
  60.   trackback(0);
  61.   output();
  62.   system("PAUSE");
  63.   return 0;
  64. }
    /*
  65. 1 1 0 0 1 15请按任意键继续. . .
  66. */




阅读(928) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~