Backtracking

1. Introduction
Backtracking is a method of exhaustive search. When a node reaches certain termination condition that means this path will not have solutions, the program will go back to the previous node and try another path.

2. Example
1. Generate all the strings of n bits.

int A[4];
int C=0;
void Print(int a[],int n){

    for(int i=0;i<n;i++){
        cout<<a[i];
    }
    cout<<endl;
    C++;
}

void Binary(int n){
    if(n<1){
        Print(A,4);
    }
    else{
        A[n-1]=0;
        Binary(n-1);
        A[n-1]=1;
        Binary(n-1);
    }
}

*Here is an example when n=4.

2. Generate all the strings of length n chosen from 0,1,,,,k-1.

int A[5];
int C=0;
void Print(int a[],int n){

    for(int i=0;i<n;i++){
        cout<<a[i];
    }
    cout<<endl;
    C++;
}

void kstring(int n,int k){
    if(n<1){
        Print(A,5);
    }
    else{
        for(int i=0;i<k;i++){
            A[n-1]=i;
            kstring(n-1,k);
        }
    }
}

*Here is an example when n=5.

3. Combination

int A[5]={1,2,3,4,5};
int R[3];
int C=0;

void Print(int a[],int n){

    for(int i=0;i<n;i++){
        cout<<a[i];
    }
    cout<<endl;
    C++;
}

void Combination(int start,int n,int a[],int r[]){
    if(n<1){
        Print(r,3);
    }
    else{
        for(int i=start;i<=5-n;i++){
            r[3-n]=a[i];
            Combination(i+1,n-1,a,r);
        }
    }
}

*Here is an example of choose 3 from 5.

4. Full permutation

Method1:

void Swap(int* a,int* b){
    int t=*a;
    *a=*b;
    *b=t;
}

void Permutation(int t[],int n,int start,int end){
    if(n<1){
        Print(t,3);
    }
    else{
        for(int i=start;i<=end;i++){
            Swap(&t[start],&t[i]);
            Permutation(t,n-1, start+1, end);
            Swap(&t[start],&t[i]);
        }
    }
}

*Here is an example of a list with 3 elements.

Method2:

const int n=5;
int numbers[5]={1,2,3,4,5};
int R[5];
int indicate[5]={0};
int C=0;

void Print(int A[],int m){
        for(int i=0;i<m;i++){
            cout<<A[i]<<' ';
        }
        cout<<endl;
    C++;
}

void Permutation(int cur){
    if(cur>=n) Print(R, n);
    else{
        for(int i=0;i<n;i++){
            if(!indicate[i]){
               R[cur]=numbers[i];
                indicate[i]=1;
                Permutation(cur+1);
                indicate[i]=0;
            }
        }
    }
}

Note that here it is necessary to have a R list to store the current solution. If we use the list numbers to store solutions, the problem is that the index of numbers will change and hence the indicate list will record the wrong situation.

5. Permutation

void Print(int a[],int n){

    for(int i=0;i<n;i++){
        cout<<a[i];
    }
    cout<<endl;
    C++;
}

void Swap(int* a,int* b){
    int t=*a;
    *a=*b;
    *b=t;
}

void Permutation(int t[],int n,int start,int end){
    if(n<1){
        Print(t,3);
    }
    else{
        for(int i=start;i<=end;i++){
            Swap(&t[start],&t[i]);
            Permutation(t,n-1, start+1, end);
            Swap(&t[start],&t[i]);
        }
    }
}

void Combination(int n,int start, int a[],int r[]){
    if(n<1){
        Permutation(r,3, 0, 2);
    }
    else{
        for(int i=start;i<=5-n;i++){
            r[3-n]=a[i];
            Combination(n-1, i+1, a, r);
        }
    }
}

*Here is an example of choose 3 from 5, the basic idea is to find all combinations first and then do full permutation to each combination.

3. Problems and solutions
1. N-Queen problem

void search(int curline){
    if(curline==n) {
        tot++;
        for(int i=0;i<n;i++){
            cout<<C[i]<<' ';
        }
        cout<<endl;
    }
    else{
        for(int i=0;i<n;i++){
            int ok=1;
            C[curline]=i;
            for(int j=0;j<curline;j++){
                if(C[curline]==C[j]||curline-C[curline]==j-C[j]||curline+C[curline]==j+C[j]){

                        ok=0;
                        break;
                    }
                }
            if(ok) search(curline+1);
            }
        }
    }

Here we use a one-dimension list to indicate the position of chess and we use mathematical relation between line and column number as if-conditions to determine whether the solution is acceptable.

We can also do this in the following method:

void search(int cur){
    if(cur==n){
        tot++;
        for(int i=0;i<n;i++){
            cout<<C[i]<<' ';
        }
        cout<<endl;
    }
    else{
        for(int i=0;i<n;i++){
            if(!vis[0][i]&&!vis[1][cur+i]&&!vis[2][i-cur+n]){
                C[cur]=i;
                vis[0][i]=vis[1][cur+i]=vis[2][i-cur+n]=1;
                search(cur+1);
                vis[0][i]=vis[1][cur+i]=vis[2][i-cur+n]=0;
            }
        }
    }
}

Here we use a two-dimensional list vis to indicate the column and diagonals that are already occupied by previous chess. Note that after recursively call function search for the next line, we need to change back the value of that position in vis for it to work on the next column of the current line.

2. Prime Ring Problem (UVa 524)

Method 1: (Enumeration, brute force)

#include <iostream>
#include <cmath>
using namespace std;

int const n=6;
int inputs[n]={1};
int isp[2*n+1];

int is_prime(int a){
    int t=sqrt(a);
    int ok=1;
    for(int i=2;i<=t;i++){
        if(a%i==0){
            ok=0;
            break;
        }
    }
    if(ok) return 1;
    else return 0;
}

void Swap(int*a, int*b){
    int t=*a;
    *a=*b;
    *b=t;
}

void Print(int A[],int m){
    for(int i=0;i<m;i++){
        cout<<A[i]<<' ';
    }
    cout<<endl;
}

void Decide(){
    int ok=1;
    for(int i=0;i<n;i++){
        if(!isp[inputs[i]+inputs[(i+1)%n]]){
            ok=0;
            break;
        }
    }
    if(ok) Print(inputs,n);
}

void Permutation(int start){
    if(start>=n){
        Decide();
    }
    else{
        for(int i=start;i<n;i++){
            Swap(&inputs[i],&inputs[start]);
            Permutation(start+1);
            Swap(&inputs[i],&inputs[start]);
        }
    }
}

int main(){
    for(int i=0;i<n;i++){
        inputs[i]=i+1;
    }

    for(int i=2;i<=2*n;i++){
        isp[i]=is_prime(i);
    }

    Permutation(1);
}

This method will exceed time limit when n gets bigger.

Method 2: (Backtracking)

#include <iostream>
#include <cmath>
using namespace std;

const int n=6;
int A[n]={1};
int vis[n]={0};

int is_prime(int a){
        int t=sqrt(a);
        int ok=1;
        for(int i=2;i<=t;i++){
            if(a%i==0){
                ok=0;
                break;
            }
        }
        if(ok) return 1;
        else return 0;
}

void Print(int A[],int m){
            for(int i=0;i<m;i++){
                cout<<A[i]<<' ';
            }
            cout<<endl;
}


void dfs(int cur){
    if(cur==n&&is_prime(A[0]+A[n-1])){
        Print(A, n);
    }
    else{
        for(int i=2;i<=n;i++){
            if(!vis[i]&&(is_prime(i+A[cur-1]))){
                A[cur]=i;
                vis[i]=1;
                dfs(cur+1);
                vis[i]=0;
            }
        }
    }
}

int main(){
    dfs(1);
}

3. Krypton Factor (UVa 129)

#include <iostream>
#include <cstdio>
using namespace std;

const int L=3;
const int n=30;
int S[200];
int cnt=0;

int dfs(int cur){
    if(cnt==n){
        for(int i=0;i<cur;i++){
            printf("%c",'A'+S[i]);
        }
        printf("\n");
        return 0;
    }
    for(int i=0;i<L;i++){
        S[cur]=i;
        int ok=1;
        for(int j=1;j<=(cur+1)/2;j++){
            int equal=1;
            for(int k=0;k<j;k++){
                if(S[cur-k]!=S[cur-k-j]){
                    equal=0;
                    break;
                }
            }
            if(equal){
                ok=0;
                break;
            }
        }
        if(ok){
            cnt++;
            if(!dfs(cur+1)){
                return 0;
            }
        }
    }
    return 1;
}

int main(){
    dfs(0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯线搜索(backtracking line search)是一种用于优化算法中的搜索技术。其基本思想是在搜索方向上进行一系列的试探,以找到一个满足一定条件的可接受步长。具体来说,假设我们在某一点 $x$ 处进行优化,搜索方向为 $d$,则回溯线搜索的过程如下: 1. 选择一个初始步长 $\alpha_0>0$,一般可以选择较小的值,比如 $\alpha_0=1$ 或 $\alpha_0=0.1$; 2. 在每一次迭代中,计算 $f(x+\alpha_k d)$,其中 $f$ 是待优化的目标函数,$k$ 表示当前的迭代次数; 3. 如果 $f(x+\alpha_k d) \leq f(x) + c_1 \alpha_k \nabla f(x)^T d$,其中 $c_1 \in (0,1)$ 是一个预回溯直线搜索(backtracking line search)是一种用于优化算法的技术,特别是用于求解无约束非线性优化问题。在每次迭代中,回溯直线搜索算法会尝试在当前搜索方向上找到一个满足一定条件的步长,使得在该步长下目标函数值可以得到显著的改善。 具体来说,回溯直线搜索算法在每次迭代中按照当前搜索方向移动一定步长,然后检查目标函数是否得到了改善。如果目标函数得到了改善,则接受该步长并继续迭代;否则,将步长缩小一定比例(通常是折半),并重复该过程,直到找到一个满足条件的步长。 回溯直线搜索算法的优点是可以在无约束优化问题中进行全局搜索,因为它可以通过改变搜索方向和步长来遍历整个搜索空间。然而,回溯直线搜索算法的缺点是它可能需要进行大量的迭代才能找到最优解,因此在实际应用中,通常需要与其他优化算法结合使用,以便在更短的时间内找到最优解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值