华师一附中OI组
标题:
P1379 八数码难题
[打印本页]
作者:
admin
时间:
2018-5-12 22:30
标题:
P1379 八数码难题
https://www.luogu.org/problemnew/show/P1379
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初始状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
输入样例#1:
283104765
输出样例#1:
4
我写的标准的单向广搜,效率不高,正确性是显然的。大家可以学学
#include <iostream>
using namespace std;
const int mm=10100;
string d[mm]; ///表示状态
int f[mm];///表示他的爸爸
int head,tail;
bool b;
string s,t; ///源和目标
string ts,tt;
string change(string s,int i)
{
///1,2,3,4 分别表示空格向上右下左运动
int x=s.find('0');
string tt=s;
if (i==1) ///向上
{
if (x>2) ///要求不在第一行
swap(tt[x],tt[x-3]);
}
if (i==2)
{
if (x%3<2) ///要求不在最后一列
swap(tt[x],tt[x+1]);
}
if (i==3)
{
if (x/3<2) ///要求不在最后一行
swap(tt[x],tt[x+3]);
}
if (i==4)
{
if (x%3>0) ///要求不在第一列
swap(tt[x],tt[x-1]);
}
return tt;
}
bool isdup(string s)
{
bool b=0;
for (int i=1; i<=tail; i++)
if (d[i]==s)
{
b=1;
break;
}
return b;
}
void pp()
{
int i=1,j;
int p[50];///最多50步,表示路径
p[1]=j=head;
while (f[j]!=0)
p[++i]=j=f[j];
cout<<i;
}
int main()
{
s="123804765";
cin>>t; ///读入状态
head=tail=1;
d[head]=s; ///初始状态入队
f[head]=0;
b=1;///未找到标记
if (s==t) cout<<0;
else
{
while (tail<=mm-1000 && tail>=head && b)
{
ts=d[head]; ///取队首元素
///cout<<ts<<endl; 输出检查
for (int i=1; i<=4; i++) ///按规则扩展
{
tt=change(ts,i);
if (tt==t)
{
b=0; ///达到终点,跳出
break;
}
if (!isdup(tt)) ///判重入队
{
tail++;
d[tail]=tt;
f[tail]=head;
}
}
head++;
}
if (!b) pp();
}
return 0;
}
复制代码
加上map优化的话,可以得90分。
#include <iostream>
#include<map>
using namespace std;
const int mm=10100;
string d[mm]; ///表示状态
int f[mm];///表示他的爸爸
int head,tail;
bool b;
string s,t; ///源和目标
string ts,tt;///临时
map<string,int> m; ///判重!!!
string change(string s,int i)
{
///1,2,3,4 分别表示空格向上右下左运动
int x=s.find('0');
string tt=s;
if (i==1) ///向上
{
if (x>2) ///要求不在第一行
swap(tt[x],tt[x-3]);
}
if (i==2)
{
if (x%3<2) ///要求不在最后一列
swap(tt[x],tt[x+1]);
}
if (i==3)
{
if (x/3<2) ///要求不在最后一行
swap(tt[x],tt[x+3]);
}
if (i==4)
{
if (x%3>0) ///要求不在第一列
swap(tt[x],tt[x-1]);
}
return tt;
}
void pp()
{
int i=1,j;
int p[50];///最多50步,表示路径
p[1]=j=head;
while (f[j]!=0)
p[++i]=j=f[j];
cout<<i;
}
int main()
{
s="123804765";
cin>>t; ///读入状态
head=tail=1;
d[head]=s; ///初始状态入队
f[head]=0;
b=1;///未找到标记
if (s==t) cout<<0;
else
{
while (tail<=mm-1000 && tail>=head && b)
{
ts=d[head]; ///取队首元素
///cout<<ts<<endl; 输出检查
for (int i=1; i<=4; i++) ///按规则扩展
{
tt=change(ts,i);
if (tt==t)
{
b=0; ///达到终点,跳出
break;
}
if (m.find(tt)==m.end()) ///判重入队
{
m.insert(pair<string,int> (tt,head));
tail++;
d[tail]=tt;
f[tail]=head;
}
}
head++;
}
if (!b) pp();
}
return 0;
}
复制代码
作者:
张笑宇
时间:
2018-6-11 21:55
为什么RE???
#include<iostream>
using namespace std;
string s;
int i,j,l,head,tail,temp;
const int mx=100010;
const int mm=4;
int dx[mx],dy[mx],d[mx];
int a[mm][mm][mx];
int fx[5]= {0,-1,0,0,+1};
int fy[5]= {0,0,-1,+1,0};
int mymap[5][5]= {0,0,0,0,0,
0,1,2,3,0,
0,8,0,4,0,
0,7,6,5,0,
0,0,0,0,0
};
bool bb(int x)
{
int k,v;
for (k=1; k<=3; k++)
for (v=1; v<=3; v++)
if (a[k][v][x]!=mymap[k][v]) return false;
return true;
}
void cc(int x)
{
int k,v;
for (k=1; k<=3; k++)
{
for (v=1; v<=3; v++)
cout<<a[k][v][x]<<" ";
cout<<endl;
}
cout<<endl;
}
int main()
{
cin>>s;
for (i=0; i<=2; i++)
for (j=0; j<=2; j++)
{
a[i+1][j+1][1]=s[3*i+j]-'0';
if (a[i+1][j+1][1]==0) dx[1]=i+1,dy[1]=j+1;
}
///cc(1);
head=1,tail=2,d[1]=0;
while (head<=tail)
{
if (bb(head))
{
cout<<d[head];
return 0;
}
int nowx=dx[head];
int nowy=dy[head];///现在的空位
for (i=1; i<=4; i++)
{
int tx=nowx+fx[i];
int ty=nowy+fy[i];///移动的位置
if (1<=tx&&tx<=3&&1<=ty&&ty<=3)///如果可以
{
for (j=1; j<=3; j++)
for (l=1; l<=3; l++)
a[j][l][tail]=a[j][l][head];
a[nowx][nowy][tail]=a[tx][ty][head];
a[tx][ty][tail]=0;///空位
dx[tail]=tx;
dy[tail]=ty;
d[tail]=d[head]+1;///cc(tail);
tail++;
}
}
head++;
}
return 0;
}
复制代码
作者:
YTC
时间:
2018-6-19 13:06
单广搜居然能卡过
#include<iostream>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
int st;
int a[5][5];
int px,py;//0的位置
queue<int> q;
map<int,int> d;
map<int,bool> v;
void unzip(int ret)
{
for(int i=3;i>=1;i--)
for(int j=3;j>=1;j--)
{
a[i][j]=ret%10;
ret/=10;
if(a[i][j]==0)
{
px=i;
py=j;
}
}
}
int hsh()
{
int ret=0;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
ret=ret*10+a[i][j];
return ret;
}
int main()
{
cin>>st;
q.push(st);
d[st]=0;
while(!q.empty())
{
int x=q.front();
q.pop();
if(x==123804765) {cout<<d[x];return 0;}
if(v[x]) continue;
v[x]=1;
unzip(x);
for(int i=0;i<=3;i++)
if(px+dx[i]>0&&px+dx[i]<=3&&py+dy[i]>0&&py+dy[i]<=3)
{
swap(a[px][py],a[px+dx[i]][py+dy[i]]);
q.push(hsh());
d[hsh()]=d[x]+1;
swap(a[px][py],a[px+dx[i]][py+dy[i]]);
}
}
return 0;
}
复制代码
作者:
黄煦喆
时间:
2018-9-23 17:02
#include<iostream>//123804765
#include<queue>
#include<map>
using namespace std;
string s,ss,ts,goal="123804765",tt;
queue<string>q;
map<string,int>m;
bool b;
string change(string x,int i)
{
int num=x.find('0');
ts=x;
if(i==1&&num>2)swap(ts[num],ts[num-3]);
else if(i==2&&num%3!=2)swap(ts[num],ts[num+1]);
else if(i==3&&num<6)swap(ts[num],ts[num+3]);
else if(i==4&&num%3!=0)swap(ts[num],ts[num-1]);
return ts;
}
int main()
{
cin>>s;
q.push(s);
m[s]=1;
while(!q.empty()&&!b)
{
tt=q.front();
q.pop();
if(tt==goal)b=1;
else for(int i=1; i<=4; i++)
{
ss=change(tt,i);
if(m[ss]==0)q.push(ss),m[ss]=m[tt]+1;
}
}
cout<<m[goal]-1;
return 0;
}
复制代码
作者:
张乐天
时间:
2019-2-11 14:57
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
string r="123804765";
map<string,int>m;
string a[1000000];///状态
int b[1000000];///次数
int h=1,t=2;
bool bb=1;
string change(int i,string k)///移动
{
string tt=k;
int x=tt.find('0');
if(i==1&&x<=5)swap(tt[x],tt[x+3]);
if(i==2&&x>=3)swap(tt[x],tt[x-3]);
if(i==3&&x%3>=1)swap(tt[x],tt[x-1]);
if(i==4&&x%3<=1)swap(tt[x],tt[x+1]);
return tt;
}
int main()
{
cin>>a[1];
b[1]=0;
if(a[1]==r)
{
cout<<0<<endl;
return 0;
}
while(h<=t&&t<=900000&&bb)
{
string xs=a[h];
int xa=b[h];
for(int i=1;i<=4;++i)
{
string tt=change(i,xs);
int tc=xa+1;
if(m.count(tt))continue;
else
{
m.insert(pair<string,int>(tt,tc));
a[t]=tt;
b[t]=tc;
if(a[t]==r)
{
cout<<b[t]<<endl;
bb=false;
return 0;
}
t++;
}
}
h++;
}
return 0;
}
复制代码
作者:
张溯源
时间:
2020-5-2 22:12
老师,这个程序看是看得懂,问题是全部超时了,开了优化之后,全不错了,满分程序怎么写
作者:
张溯源
时间:
2020-5-2 22:15
老师,这个后面一个程序(map),我试了一下,只能有19分
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2