第六章-树(7)回溯法与树的遍历

 题目一:幂集问题(组合问题) (参见《数据结构》(严蔚敏))
     求含N个元素的集合的幂集。
     如对于集合A={1,2,3},则A的幂集为
     p(A)={{1,2,3},{1,2},{1,3},{1},{2,3},{2},{3},Φ}
幂集的每个元素是一个集合,它或是空集,或含集合A中的一个元素,或含A中的两个元素,或者等于集合A。反之,集合A中的每一个元素,它只有两种状态:属于幂集的元素集,或不属于幂集元素集。则求幂集P(A)的元素的过程可看成是依次对集合A中元素进行“取”或“舍”的过程,并且可以用一棵状态树来表示。求幂集元素的过程即为先序遍历这棵状态树的过程。 

#include <stdio.h>
#include <malloc.h>
#define ERROR 0
#define OK 1

typedef int ElemType;
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
} LNode,*LinkList;

//初始化
LinkList ListInit()
{

    LNode *base=(LinkList)malloc(sizeof(LNode));
    base->data=0;
    base->next=NULL;
    return base;
}
//插入一个元素
int ListInsert(LinkList L,int i,ElemType e)
{
    LNode *p,*s;
    int j=0;
    p=(LNode *)L;
    while(p&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i-1)
        return ERROR;
    s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}
//删除一个结点
int ListDelete(LinkList &L,int i,ElemType &e)
{
    LinkList p=L,q;
    int j=0;
    while(p->next&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!(p->next)||j>i-1)
        return ERROR;
    q=p->next;
    p->next=q->next;
    e=q->data;
    free(q);
}
//长度
int ListLength(LinkList L)
{
    LinkList p=L;
    int j=0;
    if(!L)
        return ERROR;
    while(p->next)
    {
        p=p->next;
        ++j;
    }
    return j;
}
//查找一个元素
int GetElem(LinkList L,int i,ElemType &e)
{
    LNode *p=L;
    int j=0;
    while(p->next&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
        return ERROR;
    e=p->data;
    return OK;
}
//输出链表元素
void Display(LinkList L)
{
    LNode *p=L;
    if(!(p->next))
    {
        printf("NULL,");
        return;
    }
    else
        p=p->next;
    while(p)
    {

        printf("%d,",p->data);
        p=p->next;    
    }
}
//求幂集
void PowerSet(int i,LinkList A,LinkList &B)
{
    int k=0;
    ElemType e=0;
    if(i>ListLength(A))
    {
        Display(B);
        printf("\n");
    }
    else
    {
        GetElem(A,i,e);
        k=ListLength(B);
        ListInsert(B,k+1,e);      //取
        PowerSet(i+1,A,B);

        ListDelete(B,k+1,e);      //舍
        PowerSet(i+1,A,B);
    }
}

int main()
{
    LinkList list=ListInit(); //初始化
    LinkList list2=ListInit();//初始化

    ListInsert(list,1,1);//插入元素
    ListInsert(list,2,2);
    ListInsert(list,3,3);

    Display(list);//输出元素
    printf("\npower set is:\n");
    PowerSet(1,list,list2);//求幂集
}


题目二:求 4 皇后问题的所有合法布局(作为例子,我们将8皇后问题简化为4皇后)


 我们从空棋盘开始,然后把皇后1放到它所在行的第一个可能位置上,也就是第一行第—列。对于皇后2,在经过第一列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子〔2,3),位于第二行第二列的格子。这被证明是一个死胡同,因为皇后:将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(2,4)上。然后皇后3就可以放在(3,2),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(1,2)。接着皇后2到(2,4),皇后3到(3,1),而皇后4到(4,3),这就是该问题的一个解。图2给出了这个查找的状态空间树。

#include <stdio.h>
#include <math.h>
#define N  4
int col[N+1];
//输出结果
void Output()
{
    for(int i=1;i<=N;i++)
    {
        printf("(%d,%d)\n",i,col[i]);
    }
    printf("\n");
}
//求解函数
void Queen(int i,int n)
{ //进入本函数时,在n*n棋盘前 i-1 行已经放置了互不攻击的 i-1 个棋子
  //现在从第 i 行起继续为后续棋子选择合适的位置
  //当 i>n 时,求得一个合法的布局,则输出
    if(i>n)
        Output();
    else
    {
        for(int j=1;j<=n;++j)
        {
            int k=1;
            col[i]=j;    //第 i 行的第 j 列放置一个棋子
            while(k<i)   //判断是否放置合法
            {                       //fabs是取绝对值
                if((col[k]-col[i])*(fabs(col[k]-col[i])-fabs(k-i))!=0)
                {
                    k++;
                    if(k==i)
                        Queen(i+1,n);
                }
                else
                {
                    break;
                }
            }
        }
    }
}
void main()
{
    printf("the answer is:\n");
    for(int i=1;i<=N;i++)
    {
        col[1]=i; //设置第一行
        Queen(2,N); 
    }
}


转载自:http://www.cnblogs.com/hustcat/archive/2008/04/09/1144645.html




猜你喜欢

转载自blog.csdn.net/qq_40191710/article/details/79484260