hdu 3567(八数码问题 双向BFS)

题意:八数码问题,给了状态A,B,求A->B的最少变化次数,有多组最少则输出字典序最小的。可以先做这道http://acm.hdu.edu.cn/showproblem.php?pid=1043。这道简单些。

思路:双向BFS,同时从起点,终点进行搜索。这里以一个整数来表示路径。

从起点搜索,路径表示为path=oldpath*4+i

从终点搜索,路径表示为path=(3-i)*4^{step}+oldpath

这里i的取值为0~3,即空白点的不同移动所代表的数字,step表示为已走的步数。

emmmm....说了这么多,其实这道题我没A...感觉这道题很有毒,我拿网上的代码和我的代码对拍过了2000组数据还是WA。无语了,下面贴一下我的代码,网上代码还有数据生成代码。如果有大佬发现我的问题的请告知我,谢谢!!!

PS:数据生成代码也是网上找的

我的代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int fact[10];
int vis[370000][2];
ll road[370000][2];
ll p[30];

void init()
{
    fact[0]=fact[1]=1;
    for(int i=2;i<9;i++) fact[i]=fact[i-1]*i;
    p[0]=1;
    for(int i=1;i<29;i++)
    p[i]=p[i-1]*4;
}
int get(char *a)
{
    int ans=0;
    for(int i=0;i<9;i++)
    {
        int k=0;
        for(int j=i+1;j<9;j++)
        if(a[i]>a[j]) k++;
        ans+=k*fact[8-i];
    }
    return ans;
}
struct ha
{
    char num[15];
    int pos,dir,step;
    ll path;
}now,tep;
int cx[] ={3,-1,1,-3};
char op[5]="dlru";
string getway(int a,int b)
{
    //printf("%d %d\n",a,b);
    int pa[100],c=0;
    for(int i=0;i<b;i++)
    {
        pa[c++]=a%4;
        a/=4;
    }
    string ans="";
    for(int i=c-1;i>=0;i--)
        ans+=op[pa[i]];
    return ans;
}
void bfs(char* begins,char *mends)
{
    memset(vis,-1,sizeof(vis));
    memset(road,0,sizeof(road));
    queue<struct ha> qu;
    for(int i=0;i<10;i++)
    {
        now.num[i]=begins[i];
        tep.num[i]=mends[i];
    }
    now.dir=0; now.path=0; now.step=0;
    tep.dir=1; tep.path=0; tep.step=0;
    vis[get(now.num)][0]=0; vis[get(tep.num)][1]=0;
    qu.push(now); qu.push(tep);
    string apath=""; int alen=9999999;
    ll tmp;
    while(!qu.empty())
    {
        now =qu.front(); qu.pop();
        //printf("%s\n",now.num);
        for(int i=0;i<4;i++)
        {
            tep=now;
            int t=now.pos+cx[i];
            if(!((t>-1&&t<9)&&(t/3==now.pos/3||t%3==now.pos%3))) continue;

            //更新新结点信息
            tep.pos=t; swap(tep.num[t],tep.num[now.pos]);
            int tco=get(tep.num); tep.step=now.step+1;

            if(vis[tco][tep.dir]!=-1
               && (tep.step>vis[tco][tep.dir])) continue;
            //未访问过或当前步数不大于之前状态

            //求得当前路径

            if(now.dir) tmp=(3-i)*p[now.step]+now.path;
            else tmp=now.path*4+i;

            //更新road
            if(vis[tco][now.dir]!=-1)
            //保证字典序最小
            road[tco][now.dir] = min(road[tco][now.dir],tmp);
            else
            {
                vis[tco][now.dir]=tep.step; //更新vis
                road[tco][now.dir]=tmp;
            }
            tep.path=road[tco][now.dir]; //更新路径

            qu.push(tep); //入队

            if(vis[tco][!now.dir]!=-1)
            {
                string sp=getway(road[tco][0],vis[tco][0])
                +getway(road[tco][1],vis[tco][1]);
                int len=sp.length();
                if(len>alen)
                {
                    //printf("%d %d\n",vis[tco][0],vis[tco][1]);
                    printf("%d\n",alen);
                    cout<<apath<<endl;
                    return;
                }
                else if(len<alen)
                {
                    apath=sp;
                    alen=len;
                }
                else if(sp<apath) apath=sp;
            }
        }
    }
}

int main()
{
    //freopen("C:\\Users\\陈太钦\\Desktop\\in.txt","r",stdin);
    freopen("C:\\Users\\陈太钦\\Desktop\\out2.txt","w",stdout);
    init();
    int T,c=0; scanf("%d",&T);
    while(T--)
    {
        char s[10],s1[10]; scanf("%s%s",s,s1);
        int begins[10],mends[10];
        for(int i=0;i<9;i++)
        {
            if(s[i]<'0'||s[i]>'9') s[i]='0',now.pos=i;
            //else begins[i]=s[i]-'0';
            if(s1[i]<'0'||s1[i]>'9') s1[i]='0',tep.pos=i;
            //else mends[i]=s1[i]-'0';
        }
        //printf("%d %d\n",get(s),get(s1));
        printf("Case %d: ",++c);
        if(strcmp(s,s1)==0)
        {
            printf("0\n\n");
            continue;
        }
        bfs(s,s1);
    }
    return 0;
}

网上代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define LL long long int
#define MAXN 363880
using namespace std;

int power[15]={1,1,2,6,24,120,720,5040,40320,362880,3628800};
char begi[15] ,en[15] ;
int dir[4]={3,-1,1,-3} ,pos_b ,pos_e ;
char word[5]="dlru" ;
int visit[MAXN+10][2] ;
LL road[MAXN+10][2] ,p2[55] ;

struct node
{
    int step ,k ,pos_0 ;
    LL way ;
    char temp[15];
    node(){}
    node(const char a[],const int b,const LL c,const int d,const int e)
    {
        memset(temp,0,sizeof temp);
        strcpy(temp,a);
        step=b ,way=c ,k=d ,pos_0=e ;
    }
}n ;

int Hash(char a[])
{
    int ans=0 ,tmp ;
    for(int i=0;i<9;i++)
    {
        tmp=0;
        for(int j=i+1;j<9;j++)
            if(a[i]>a[j])
                tmp++;
        ans+=tmp*power[8-i];
    }
    return ans;
}

string get_way(LL a,int b)
{
    int str[100] ,cnt=0 ;
    for(int i=1;i<=b;++i)
    {
        str[++cnt]=a%4;
        a/=4;
    }
    string ans="";
    for(int i=cnt;i>0;--i)
        ans+=word[str[i]];
    return ans;
}

void bfs()
{
    if(strcmp(begi,en)==0)
    {
        printf("0\n\n");
        return;
    }
    memset(visit,-1,sizeof visit);
    memset(road,0,sizeof road);

    queue<node>point;
    point.push(node(begi,0,0,0,pos_b));
    visit[Hash(begi)][0]=0;
    point.push(node(en,0,0,1,pos_e));
    visit[Hash(en)][1]=0;

    char temp[15] ;
    int pos_0 ,lin ,pos ,ans=1<<30;
    LL tmp ;
    string anspath="";
    while(!point.empty())
    {
        n=point.front();
        pos_0=n.pos_0 ;
        strcpy(temp,n.temp);
        point.pop();

        for(int i=0;i<4;++i)
        {
            pos=pos_0+dir[i];
            if(pos>-1&&pos<9&&(pos/3==pos_0/3||pos%3==pos_0%3))
            {
                swap(temp[pos_0],temp[pos]);
                lin=Hash(temp);

                if(visit[lin][n.k]!=-1)
                {
                    if(n.step+1>visit[lin][n.k])
                    {
                        swap(temp[pos_0],temp[pos]);
                        continue;
                    }
                    if(n.k)
                        tmp=(3-i)*p2[n.step]+n.way;
                    else tmp=n.way*4+i;
                    road[lin][n.k]=min(road[lin][n.k],tmp);
                }
                else
                {
                    visit[lin][n.k]=n.step+1;
                    if(n.k)
                        road[lin][1]=(3-i)*p2[n.step]+n.way;
                    else road[lin][0]=n.way*4+i;
                }

                if(visit[lin][!n.k]!=-1)
                {
                    string path=get_way(road[lin][0],visit[lin][0])+get_way(road[lin][1],visit[lin][1]);
                    int len=path.size();
                    if(len>ans)
                    {
                        //printf("%lld %lld\n",road[lin][0],road[lin][1]);
                        printf("%d\n",ans);
                        cout<<anspath<<endl;
                        return;
                    }
                    else if(ans>len)
                    {
                        ans=len;
                        anspath=path;
                    }
                    else if(anspath>path)
                        anspath=path;
                }
                point.push(node(temp,n.step+1,road[lin][n.k],n.k,pos));
                swap(temp[pos_0],temp[pos]);
            }
        }
    }
}

int main()
{
    //freopen("C:\\Users\\陈太钦\\Desktop\\in.txt","r",stdin);
    freopen("C:\\Users\\陈太钦\\Desktop\\out1.txt","w",stdout);
    p2[0]=1;
    for(int i=1;i<=28;++i)
        p2[i]=p2[i-1]*4;
    int T ;
    scanf("%d",&T);
    for(int cas=1;cas<=T;++cas)
    {
        scanf("%s%s",begi,en);
        for(int i=0;i<9;++i)
        {
            if(begi[i]=='X')
                pos_b=i,begi[i]='0';
            if(en[i]=='X')
                pos_e=i,en[i]='0';
        }
        printf("Case %d: ",cas);
        bfs();
    }
    return 0;
}

数据生成代码:

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;

const int maxn=1e3+10;
int f[maxn],g[maxn];
void random(int t)
{

    int i,j,k,m,num=0;
    for(i=0;i<t;i++)f[i]=i;
    m=t;
    for(i=0;i<t;i++)
    {
        num=rand()%m;
        g[i]=f[num];
        f[num]=f[m-1];
        m--;
    }
}
int judge()
{
    int i,j,k=0;
    for(i=0;i<9;i++)
    {
        //printf("%c\n",e.c[i]);
        if(g[i]==0)continue;
        for(j=0;j<i;j++)
        {
            if(g[j]==0)continue;
            if(g[j]>g[i])k++;
        }
    }
    return k%2;
}
int main()
{
    freopen("C:\\Users\\陈太钦\\Desktop\\in.txt","w",stdout);
    srand(time(NULL));
    int i,j,k,n;
    printf("2000\n");
    for(i=0;i<2000;i++)
    {
        random(9);
        k=judge();
        for(j=0;j<9;j++)
        {
            if(g[j]==0)
                printf("X");
            else
                printf("%d",g[j]);
        }
        printf("\n");
        do
        {
            random(9);
        }while(k!=judge());
        for(j=0;j<9;j++)
        {
            if(g[j]==0)
                printf("X");
            else
                printf("%d",g[j]);
        }
        printf("\n");
    }
}
/*
#include<bits/stdc++.h>
using namespace std;
int main()
{
    freopen("C:\\Users\\陈太钦\\Desktop\\in2.txt","r",stdin);
    char s[4000][400];
    for(int i=0;i<4000;i++) scanf("%s",s[i]);
    //for(int i=0;i<400;i++) printf("%s\n",s[i]);
    for(int i=0;i<2000;i++)
    if(strcmp(s[i],s[i+2000])!=0) printf("%d %s %s\n",i,s[i],s[i+2000]);
    return 0;
}*/

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值