回溯法的应用举例

子集合问题

  求集合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算法训练 开心的金明

拥抱明天! 不给自己做枷锁去限制自己。 别让时代的悲哀,成为你人生的悲哀。
原文地址:https://www.cnblogs.com/dd2hm/p/7418935.html