• 回溯法的应用举例


    子集合问题

      求集合S的所有子集合(不包括空集),可以按照框架一的算法写代码。

     1 #include<iostream>
     2 using namespace std;
     3 int s[4]={3,5,7,9};
     4 int x[4];
     5 int N=4;
     6 
     7 void print() {
     8     for(int j=0;j<N;j++)
     9      if(x[j]==1) 
    10          cout<<s[j]<<" ";
    11      cout<<endl;
    12 }
    13 
    14 void SubSet(int i) {
    15     if(i>=N) {
    16         print();
    17         return;
    18     }
    19     x[i]=1;
    20     SubSet(i+1);
    21     x[i]=0;
    22     SubSet(i+1);
    23 }
    24 int main() {
    25     cout<<"数组的子集合为: "<<endl;
    26     SubSet(0); 
    27     return 0;
    28 }
    View Code

    在此基础上,求解有条件限制的子集合问题,例如,整数集合s和一个整数sum,求集合s的所有子集su,使得su的元素之和等于sum。

    #include <stdio.h>
    int flag,sum=0;
    int *s, *x, n,c;
    
    
    void backtrack(int t)
    {
        int i;
        if(t==n)
        {
            if(sum==c)
            {
                flag=1;
                for(i=0;i<n;i++)
                    if(x[i])
                        printf("%3d",s[i]);
    
                printf("
    ");
                return;
            }
        }
        else
        {
            sum+=s[t];
            x[t]=1;
            backtrack(t+1);
            x[t]=0;
            sum-=s[t];
            backtrack(t+1);
        }
    }
    
    int main()
    {
    
        int i;
    
        scanf("%d%d",&n,&c);
        s=new int [n];
        x=new int[n];
    
        for(i=0;i<n;i++){
            scanf("%d",&s[i]);
            x[i]=0;
        }
    
        backtrack(0);
    
        if(flag)
            printf("yes");
        else 
            printf("no");
    
        return 0;
    }
    View Code

    相关资料可以看子集和问题 

    回溯法解决子集和问题http://blog.sina.com.cn/s/blog_7865b083010100dd.html

     

    全排列问题

      求一个集合元素的全排列,可以按照框架二写出代码

    #include<iostream>
    using namespace std;
    int a[4]={3,5,7,9};
    const int N=4;
    
    void print() {
        for(int i=0;i<N;i++)
            cout<<a[i]<<" ";
        cout<<endl;
    }
    
    void swap(int *a,int i,int j) {
        int temp;
        temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
    
    void backtrack(int i) {
        if(i>=N) {
            print();
        }
        for(int j=i;j<N;j++) {
            swap(a,i,j);
            backtrack(i+1);
            swap(a,i,j);
        }
    }
    
    int main() {
        cout<<"所有组合为: "<<endl;
        backtrack(0); 
        return 0;
    }
    View Code

    八皇后问题

     (1)定义问题的解空间。这个问题解空间就是8个皇后在棋盘上的位置、

     (2)定义解空间的结构。可以使用8*8的数组,但由于任意两个皇后都不能再同行,可以用数组下标表示行,数组的值来表示数组的列,可以简化为一个一维数组x[9];

     (3)以深度优先方式搜索解空间,并在搜索过程使用剪枝函数来剪枝。根据条件x[i]==x[k]判断处于同一列,abs(k-i)==abs(x[k]-x[i])判断是否处于同一斜线,剪枝函数如下:

    bool canPlace(int k) {
        for(int i=1;i<k;i++) {
            if(x[i]==x[k] || abs(k-i)==abs(x[k]-x[i]))    return false;
        }
        return true;
    }

      按照回溯框架一,八皇后回溯代码如下:

    void queue(int i) {
        if(i>8) {
            print();
            return;
        }
        for(int j=1;j<=8;j++) {
            x[i]=j;//记录所放的列 
            if(calPlace(i)) queue(i+1);
        }
    }

    完整代码:

    #include<iostream>
    #include<cmath>
    using namespace std;
    int x[9];
    int count=1;
    void print() {
        cout<<count<<":";
        for(int i=1;i<=8;i++) 
            cout<<x[i]<<" ";
        cout<<endl;
        count++;
        
    }
    
    bool canPlace(int k) {
        for(int i=1;i<k;i++) {
            if(x[i]==x[k] || abs(k-i)==abs(x[k]-x[i]))    return false;
        }
        return true;
    }
    
    void queue(int i) {
        if(i>8) {
            print();
            return;
        }
        for(int j=1;j<=8;j++) {
            x[i]=j;//记录所放的列 
            if(canPlace(i)) queue(i+1);
        }
    }
    int main() {
        queue(1); 
        return 0;
    }
    View Code

    简单方法解决八皇后问题

    0-1背包问题

      问题:给定n种物品和一背包。物品i的重点是Wi,其价值是ui,背包的容量是C。如何选择装入背包的物品,使得装入背包中物品的总价值最大、

      0-1背包是子集合选取问题,问题分析步骤如下:

      (1)确定解空间。即确定装入何种物品、

      (2)确定易于搜索的解空间结构。可以用数组p,w分别表示各个物品价值和重量。

      用数组x记录,是否选中物品。

      (3)以深度优先方式搜索解空间,并在搜索的过程中剪枝。

    算法训练 开心的金明

    算法训练 入学考试

    ALGO-21 算法训练 装箱问题

    ALGO-31算法训练 开心的金明

    拥抱明天! 不给自己做枷锁去限制自己。 别让时代的悲哀,成为你人生的悲哀。
  • 相关阅读:
    [转]Splay算法
    [转]模拟退火算法
    [转]九种背包问题
    [转]C++实现平衡二叉树
    关于set
    __builtin_popcount
    为什么调用线程的join方法,等待的是执行join方法的线程
    volatile and 指令重排序 (单例模式用volatile来声明单例对象)
    线程池
    sts 转用 IDEA随记
  • 原文地址:https://www.cnblogs.com/dd2hm/p/7418935.html
Copyright © 2020-2023  润新知