实验二 隐示图的搜索问题(源码)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h> 
#include<time.h> 
#include<stdlib.h> 
#include<string.h> 
#include<math.h> 
#define SIZE 3 //宏
#define SIZESQR 9 

long total;
typedef char board[SIZE][SIZE];//二维数组
board target = { 1,2,3,4,5,6,7,8,0 };  // 目标状态 
typedef struct mynode {//结构体
    board data;  //存放状态 
    struct mynode* parent; //存放父节点地址 
    struct mynode* child[4]; //存放子节点地址,最多4个 
    struct mynode* next;  //索引指针 下一个指向的是谁
    int f, h, g, how; //how中记录了其父节点如何移动生成该节点 
}Node, * List;

void Nodeini(Node* nodep);
int geth();
int cansolve(Node* start);
int goal(board temp);

Node* head;
Node* stack[50], * p;
int top = 0;

void Nodeini(Node* nodep)//初始化 
{
    memset(nodep, 0, sizeof(Node));
}
int geth(Node* nodep)//计算h值(h值为每个节点与其目标位的总和) 
{
    int i, j, x, y, h = 0;
    for (i = 0; i < SIZE; i++)
        for (j = 0; j < SIZE; j++)
            for (x = 0; x < SIZE; x++)
                for (y = 0; y < SIZE; y++)
                    if (target[x][y] == nodep->data[i][j] && target[x][y])
                        h += abs(x - i) + abs(y - j);
    return h;
}


void push(Node* stack[], Node* p, int* top)
{
    stack[(*top)++] = p;
}

Node* pop(Node* stack[], int* top)
{
    return stack[--(*top)];
}

int cansolve(Node* start)     // 搜索前判断是否可解,如果逆序的奇偶性相同则可解,反之则不可解 
{
    long i, j, k1, k2;

    for (i = 0; i < SIZE; i++)
    {
        for (j = 0; j < SIZE; j++)
        {
            if (!start->data[i][j])
            {
                start->data[i][j] = SIZESQR;
                k1 = (SIZE - 1 - i) + (SIZE - 1 - j);
            }
            if (!target[i][j])
            {
                target[i][j] = SIZESQR;
                k2 = (SIZE - 1 - i) + (SIZE - 1 - j);
            }
        }
    }
    for (i = 0; i < SIZESQR; i++)
    {
        for (j = i + 1; j < SIZESQR; j++)
        {
            if (start->data[i / SIZE][i % SIZE] > start->data[j / SIZE][j % SIZE]) k1++;
            if (target[i / SIZE][i % SIZE] > target[j / SIZE][j % SIZE]) k2++;
        }
    }
    for (i = 0; i < SIZE; i++)
    {
        for (j = 0; j < SIZE; j++)
        {
            if (start->data[i][j] == SIZESQR) start->data[i][j] = 0;
            if (target[i][j] == SIZESQR) target[i][j] = 0;
        }
    }
    return (k1 % 2) == (k2 % 2) ? 1 : 0;
}
//判断temp状态是否是目标状态 
int goal(board temp)
{
    if (memcmp(temp, target, sizeof(target)))
        return 0;
    return 1;
}
//返回0所在的坐标 
void getxy(Node* temp, int* x, int* y)
{
    int i, j;
    for (i = 0; i < SIZE; i++)
    {
        for (j = 0; j < SIZE; j++)
            if (!temp->data[i][j])
            {
                *x = i;
                *y = j;
            }
    }
}
void new_node(Node* p, int* index, int how, int x, int y, int xi, int yi)//移动操作(节点指针,子节点序号,移动方向,x,y,x偏移量,y偏移量) 
{
    int i, j, k;
    char tmp;
    i = *(index);
    p->child[i] = (List)malloc(sizeof(Node));
    Nodeini(p->child[i]);
    for (k = 0; k < SIZE; k++)
    {
        for (j = 0; j < SIZE; j++)
        {
            p->child[i]->data[k][j] = p->data[k][j];
        }
    }
    tmp = p->child[i]->data[x][y];
    p->child[i]->data[x][y] = p->data[x + xi][y + yi];
    p->child[i]->data[x + xi][y + yi] = tmp;
    p->child[i]->parent = p;
    p->child[i]->h = geth(p->child[i]);
    p->child[i]->g = p->g + 1;
    p->child[i]->how = how;
    p->child[i]->f = p->child[i]->h + p->child[i]->g;
    i++;
    total++;
    *index = i;
}
//扩展p所指向的节点 
void expand(Node* p) {
    int x, y, i = 0, j = 0, k = 0;
    Node* temp, * lasttemp;
    getxy(p, &x, &y);
    //y!=0(左边有节点)并且how!=4(不是父节点右移得到的),进行左移 
    if (y != 0 && p->how != 4)
        new_node(p, &i, 1, x, y, 0, -1);
    if (y != 2 && p->how != 1)
        new_node(p, &i, 4, x, y, 0, 1);
    if (x != 0 && p->how != 3)
        new_node(p, &i, 2, x, y, -1, 0);
    if (x != 2 && p->how != 2)
        new_node(p, &i, 3, x, y, 1, 0);
    //插入open表 
    for (j = 0; j < i; j++)
    {
        if (!head || (head->f >= p->child[j]->f))
        {
            temp = head;
            head = p->child[j];
            p->child[j]->next = temp;
        }
        else
        {
            temp = head;
            lasttemp = temp;
            while (temp && (temp->f < p->child[j]->f))
            {
                lasttemp = temp;
                temp = temp->next;
            }
            if (!lasttemp->next)
                p->child[j]->next = NULL;
            else
                p->child[j]->next = temp;
            lasttemp->next = p->child[j];
        }
    }
    p->next = head;
}

void main()
{
    Node begin;//初始化
    Node* start, * temp, * tempn;
    int a[SIZESQR];
    int i, j, k, ix, jx;
    char ch;

    while (1)
    {
        total = 1;
        //输入原始状态 
        Nodeini(&begin);
        start = &begin;

        printf("┏━━━━━┓\n");
        printf("┃   菜单   ┃\n");
        printf("┃1.手动输入┃\n");
        printf("┃2.随机生成┃\n");
        printf("┃0.退出程序┃\n");
        printf("┗━━━━━┛\n");
        scanf(" %c", &ch);

        if (ch == '0')
            break;
        else if (ch == '1')
        {
            printf("\n请输入初始状态:\n");
            for (i = 0; i < SIZE; i++)
            {
                for (j = 0; j < SIZE; j++)
                {
                    scanf("%ld", &k);
                    start->data[i][j] = k;
                }
            }
        }
        else
        {
            srand((unsigned)time(NULL));     //随机时间种子 

            for (i = 0; i < SIZE; i++)
            {
                for (j = 0; j < SIZE; j++)
                {
                    k = (int)(rand()) % SIZESQR;
                    start->data[i][j] = k;
                    a[i * SIZE + j] = k;

                    for (k = 0; (k < i * SIZE + j) && (i + j); k++)
                        if (start->data[i][j] == a[k]) { j--; break; }
                }
            }
        }
        printf("\n初始状态为:\n");

        printf("┏━━━┓\n");
        for (i = 0; i < SIZE; i++)
        {
            printf("┃");
            for (j = 0; j < SIZE; j++)
                printf("%d ", start->data[i][j]);
            printf("┃");
            printf("\n");
        }
        printf("┗━━━┛\n");

        printf("\n目标状态为:\n");

        printf("┏━━━┓\n");
        for (i = 0; i < SIZE; i++)
        {
            printf("┃");
            for (j = 0; j < SIZE; j++)
                printf("%d ", target[i][j]);
            printf("┃");
            printf("\n");
        }
        printf("┗━━━┛\n");

        printf("是否要修改目标状态?(y/n):\n");
        scanf(" %c", &ch);
        if (ch == 'Y' || ch == 'y')
        {
            printf("请输入新的目标状态:\n");
            for (i = 0; i < SIZE; i++)
            {
                for (j = 0; j < SIZE; j++)
                {
                    scanf("%ld", &k);
                    target[i][j] = k;
                }
            }
        }

        //判断是否能到目标状态 
        if (!cansolve(start))
        {
            printf("This puzzle is not solvable.\n");
            continue;
        }

        //对原始状态节点进行初始化 
        start->g = 0;
        start->how = 0;
        start->h = geth(start);
        start->f = start->h + start->g;
        head = start;
        //加入open表,head为头指针 

        while (1)
        {
            if (goal(head->data))
                break;
            //将tempn(原来的head)从open表中删除 
            tempn = head;
            head = head->next;
            //扩展tempn 
            expand(tempn);
            //对open表进行排序 
            i = 0;
            while (tempn->child[i] && (i < 4)) i++;
        }

        j = -1;
        top = 0;
        //输出结果 
        while (head)
        {
            push(stack, head, &top);
            head = head->parent;
            j++;
        }
        while (top)
        {
            p = pop(stack, &top);

            printf("┏━━━┓\n");

            for (ix = 0; ix < SIZE; ix++)
            {
                printf("┃");
                for (jx = 0; jx < SIZE; jx++)
                    printf("%d ", p->data[ix][jx]);
                printf("┃");

                printf("\n");
            }
            printf("┗━━━┛\n");

            if (top)printf("    \\/ \n");
        }
        printf("总共%d步!\n", j);
        printf("生成节点数:%8ld\n", total);
        start = start->next;
        while (start)
        {
            temp = start;
            start = start->next;
            free(temp);
        }
        printf("\n是否继续?(y/n):");
        scanf(" %c", &ch);
        if (ch == 'n' || ch == 'N') break;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值