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