暴力求解法_回溯法(八皇后问题,素数环,困难的串)

回溯法

当把问分成若干个不走并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现在称为回溯

八皇后问题

史上最经典的问题了,感觉哪里都能看到它,人工智能,算法?hhh好像也就这些,但是哪里都有它hhh

输出:

0 1
1 1
2 0
3 0
4 2
5 10
6 4
7 40
8 92
9 352
10 724
11 2680
12 14152
13 70860
14 288980
15 1308958
16 4310906
code:
#include 
const int MAXN=20;
int vis[MAXN][MAXN];
int C[MAXN];
int tot=0;
void search(int cur,int m){
    int i,j;
    if(cur==m) tot++;
    else for(i=0;i//利用二维数组直接判断
        if(!vis[0][i]&&!vis[1][cur+i]&&!vis[2][cur-i+m]){
            C[cur]=i;
            vis[0][i]=vis[1][cur+i]=vis[2][cur-i+m]=1;
            search(cur+1,m);
            vis[0][i]=vis[1][cur+i]=vis[2][cur-i+m]=0;
        }
    }
}
int main() {
//  scanf("%d",&n);
    int n;
    for(n=0;n<=16;n++){
    search(0,n);
    printf("%d %d\n",n,tot);
    tot=0;
    }
    return 0;
}

素数环

题目:输入整数n,把整数1,2,3…,n组成一个环,使得相邻的整数之和为素数。输出时从整数n开始逆时针输出排列。同一个环应该恰好输出一次。

输入:

6

输出:

1 4 3 2 5 6 
1 6 5 2 3 4 

首先回顾素数的判断,将每个数循环一遍判断是否为素数,如果为素数就在标记数组isp对应的位置输出1,如果不是则为0。

接着是打印过程,以cur==n && isp[A[0]+A[n-1]]为界限,表示你已经组成了哪个刚刚好的循环了,输出。

接着就是回溯了,创建循环,每个数遍历一遍,如果没有访问过而且满足和前一个数相加为素数,就标记。然后回溯下一个数组的元素,也就是cur+1.

code:

#include 
#include
#include
#include
using namespace std;
const int MAXN=10010;
int isp[MAXN];  //判断相加后的结果是否为素数
int A[MAXN];//存储数组
int vis[MAXN];//标记是否使用过该值
int n;
int is_prime(int x){
    if(n<=1)        return 0;
    int k=floor(sqrt(x)+0.5);
    for(int i=2;i<=k;i++)
        if(x%i==0)  return 0;
    return 1;
}
void dfs(int cur){
    if(cur==n && isp[A[0]+A[n-1]]){
        for(int i=0;iprintf("%d ",A[i]);//打印方案
        printf("\n");
    }
    else for(int i=2;i<=n;i++){//尝试的放置每个i值
        if(!vis[i] && isp[i+A[cur-1]]){
            A[cur]=i;
            vis[i]=1;
            dfs(cur+1);
            vis[i]=0;
        }
    }
}
int main() {
    int flag=0;
    while(scanf("%d",&n)!=EOF && n>0){
        if(flag>0)  printf("\n");
        printf("%d\n",++flag);
        for(int i=2;i<=n*2;i++)  isp[i]=is_prime(i);
        memset(vis,0,sizeof(vis));
        A[0]=1;
        dfs(1);
    }
    return 0;
}

困难的串

题目:如果一个字符串包含两个相邻的重复子串,则称他为“容易的串”,其他串为“困难的串”。输入正整数n和L,输出由前L个字符组成的,字典序第k小的困难的串。

输入:

7 3
30 3

输出:

ABACABA
ABACABCACBABCABACABCACBACABACB

code:

#include 
#include
int n,L;
const int MAXN=1001;
int S[MAXN];
int dfs(int cur){
    if(cur==n){//终止条件,到达第七个数,截止。
        for(int i=0;iprintf("%c",'A'+S[i]);
            printf("\n");
            return 0;
    }
    for(int i=0;iint ok=1;
        for(int j=1;j*2<=cur+1;j++){
            int equal=1;
            for(int k=0;k//检查前半段和后半段是不是一样
                if(S[cur-k]!=S[cur-k-j]){
                    equal=0;break;
        //只要有一个不相等就等于针对这个j值存在不想等,接着是判断下一个j++的值
                }
            }
            if(equal) {ok=0;break;}//后半段等于前半段,方案不合理
        }
        if(ok) if(!dfs(cur+1)) return 0;
        //判断完所有的j值之后,知道不满足for循环的条件就跳出
    }
    return 1;
}

int main() {
    while(scanf("%d %d",&n,&L)!=EOF){
        dfs(0);
        memset(S,0,sizeof(S));
    }
    return 0;
}

你可能感兴趣的:(算法竞赛入门,暴力求解法)