回溯法与树的遍历

回溯法:其求解过程实质是一个先序遍历一棵“状态树”的过程,只是这棵树不是遍历前预先建立的,而

是隐含在遍历过程中。


题目描述:求含n个元素的集合的幂集。

例:A={1,2,3},则A的幂集为{{1,2,3},{1,2},{1, 3},{2,3},{1},{2},{3},{}}

解题思路:求幂集的过程可看成是依次对集合A中的元素进行取或舍的过程。

1.       选择合适的数据结构——假设以线性表表示集合。

2.       树根结点表示幂集元素的初始状态(空集),叶子结点表示终结状态(幂集的元素),第i层表

示已对前i-1个元素进行了取舍的当前状态


编码:

#include "stdafx.h"
#include <iostream.h>

#define N 10

typedef struct 
{
int data[N];
int length;
}SqList;

//输出线性表B
void Output(SqList &B)
{
int i;
if(B.length ==0)
   cout<<"空集\n";
else
{
   for(i=0;i<B.length ;i++)
    cout<<B.data [i]<<"\t";
   cout<<endl;
}


}

//求集合A的幂集,其中B为暂存幂集元素的线性表,i表示从第i个元素开始取舍,当
//i>n时则求得幂集的一个元素,并输出
void GetPowerSet(int i,SqList A,SqList &B)
{
int x,k,j;
if(i>=A.length )
   Output(B);
else
{
   x=A.data [i];
   k=B.length ;
   B.data [k]=x;
   B.length ++;
   GetPowerSet(i+1,A,B);
   B.length --;
   GetPowerSet(i+1,A,B);
}
}
A={1,2,3},则A的幂集为{{1,2,3},{1,2},{1, 3},{2,3},{1},{2},{3},{}}

int main(int argc, char* argv[])
{
SqList A,B;
int i;
cout<<"输入A集合的元素个数\n";
cin>>A.length ;
cout<<"输入A集合的元素\n";
for(i=0;i<A.length ;i++)
   cin>>A.data [i];
B.length =0;
GetPowerSet(0,A,B);

return 0;
}

八皇后问题的实现(C语言)

八皇后问题主要靠回溯的方法实现, 与迷宫的实现相似, 但又困难了一些. 如迷宫的路径不因为上一步而改变, 八皇后的每一步都受约束于以前的步数, 并且, 迷宫只要找出一条路径就行,但八皇后则有很多的解法. 等等.

#include <stdio.h>

#define N 8           // 定义棋盘的格数, 通过改变,也可以是4皇后, 16皇后, 9皇后什么的.

int chess[N][N] = {0}; // 棋盘

int count = 0; // 有多少种放法

int canput(int row, int col) // 确定某一格能不能放

{

int i,j;

for(i = 0; i < N; i ++)

{

   if(chess[i][col] == 1) //有 同列的

   {

    return 0;

   }

   for(j = 0; j < N; j++)

   {

    if(chess[row][j]==1) //有同行的

    {

     return 0;

    }

    if(((i-row)==(j-col)||(i-row)==(col-j))&&chess[i][j]==1) // 对角线上有的

    {

     return 0;

    }

   }

}

return 1;

}

void print_chess() // 打印放置的方案

{

int i, j;

for(i = 0; i < N; i++)

{

   for(j = 0; j < N; j++)

   {

    printf("%d ", chess[i][j]);

   }

   printf("\n");

}

printf("\n");

}

 

int put(int row)     // 放置棋子, row是从哪一行开始, 通常是0

{

int j, s;

for(j = 0; j < N; j++) // 此一行的每一个格子都要试试能不能放

{

   if(canput(row, j)) // 假如这格能放的话

   {

    chess[row][j] = 1; // 放置

 

    if(row == N-1) // 已经到了最后一行, 那么肯定成功******************************************************

    {

     count = count +1;

 print_chess();

     chess[row][j] = 0; //成功后, 寻找下一种方法

     continue;

    }

    s = put(row+1); // 放置下一行的

    if(s == 0)    // 假如下一行不能放

    {chess[row][j] = 0; // 那么这格是放错了的, 清除

     continue;           // 找本行的下一个方格

    }

    else

    {

     break;

    }  

   }

}

if(j==N)    // 如果这一行的每个空格都不能放置

{

   return 0; // 那么本行放置失败

}

else

{

   return 1; // 本行放置成功

}

}

 

int main()

{

int s ;

s = put(0); // 放置

printf("the number of put way is %d\n", count); //打印信息

return 0;

}

 这个程序有个奇怪的地方, 就是在有星号的那一行, 当把chess[row][j] = 0, continue;两句去掉时,发现程序依然能正常运行. 原因就是: 当行比列多时, 假如皇后是的数目是列那么多, 是肯定放不成功的, 所以, 当程序要在最后一行的下一行放皇后时,怎么放也不成功,所以, 程序会不断调整以前的方法,但打印信息却在这里执行, 所以能打出正确信息. 但不建议去掉, 因为操作未知内存终究不是件好事.

转载于:https://www.cnblogs.com/zhangjunjie/p/3368269.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值