天天看點

hdu 3567(八數位問題 雙向BFS)

題意:八數位問題,給了狀态A,B,求A->B的最少變化次數,有多組最少則輸出字典序最小的。可以先做這道http://acm.hdu.edu.cn/showproblem.php?pid=1043。這道簡單些。

思路:雙向BFS,同時從起點,終點進行搜尋。這裡以一個整數來表示路徑。

從起點搜尋,路徑表示為

hdu 3567(八數位問題 雙向BFS)

從終點搜尋,路徑表示為

hdu 3567(八數位問題 雙向BFS)

這裡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;
}*/