广度优先搜索——神奇的题目们(第一弹)

First,我们请出在OI界风靡一阵的难题,八数码难题(其实说难也不难):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[10],b[10]={0,1,2,3,8,0,4,7,6,5},chan[1000011][10];
int pd[10][10][10][10][10][10][10][10]={0};
int w[5]={0,-3,3,-1,1};
int zero[1000011],ans[1000011];
int finish(int tail){
    for(int i=1;i<=9;i++)
        if(b[i]!=chan[tail][i])return 0;//和目标比较每一位,看看是不是目标 
    return 1;//没有退出代表到了目标 
}
void inser(int tail,int head,int wi){
    int i;
    for(i=1;i<=9;i++)
        chan[tail][i]=chan[head][i];//把父亲的状态全部赋给新节点 
    int open=zero[head]+wi;//找到新建的0的位置 
    int now=zero[head];//以前0的位置 
    chan[tail][now]=chan[tail][open];
    chan[tail][open]=0;//交换 
    zero[tail]=open;//记录现在0的位置 
    ans[tail]=ans[head]+1;//记录步数 
}
int hefa(int p,int k){
    int open=zero[k]+p;
    int pp=zero[k];
    if(open<1 || open>9)return 0;//超界 
    if(p==-1 &&(pp==4 || pp==7))return 0;
    if(p==1 &&(pp==3 || pp==6))return 0;//我们要把一维数组想象成二维数组,然后就去想吧 
    return 1;//可以拓展 
}
int ok(int tail){
    if(pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]])return 0;//如果曾经使用过,就不能再走 
    pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]]=1;return 1;//把它赋为1,返回值为1. 
}
void bfs(){
    int head=0,tail=1;
    do{
        head++;
        for(int i=1;i<=4;i++){
            if(hefa(w[i],head)){//如果可以入队 
                tail++;
                inser(tail,head,w[i]);//加入队列 
                if(!ok(tail))tail--;//被使用过 
                if(finish(tail)){//完成了 
                        printf("%d\n",ans[tail]);   
                        exit(0);//找到了就输出,结束程序 
                }
            }
        }
    }while(head<tail);
}
int main(){
    int i,j,k,n,m,head,tail;
    int fi,fj;
    for(i=1;i<=9;i++){
        char c;
        scanf("%c",&c);
        a[i]=c-'0';
        if(!a[i]){
            fi=i;
        }
        chan[1][i]=a[i];
    }//模拟字符串读入,转成数组 
    tail=1; 
    zero[tail]=fi;//队列初始化 
    pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]]=1;//用一个八维数组来判断重复,实现O(1)的复杂度判重 
    bfs();//广搜,但建立在问题一定有结果的情况下. 
    return 0;
}

这段代码的核心思想,就是判重:不需要很多的步骤,只需要简单的O(1),但是却让我们失去了太多的空间:10^9!!!要么损时,要么损空。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值