问题 D: 神奇密码锁
时间限制: 2 Sec 内存限制: 128 MB提交: 204 解决: 53
[ 提交][ 状态][ 讨论版]
题目描述
小明忘记了旅行箱上的密码,现在他想自己暴力弄出密码来,但他又想知道最从一个数字到另一个数字最少需要多少步,现在请你帮忙。
另外,小明的密码箱很奇怪,只有四位数,上面的数字只有1到9,每次只能让每位数加1或者减1。按常识我们可以知道从1到9只需要减1,从9到1只需要加1。此外,你还能交换相邻的两个数字。如1234可以在一步后变成2134,但不能变成4231。
输入
第一行有一个整数:T,代表有多少组测试数据。
接下来T行,每行有两个整数(都是四位数),第一个是初状态,第二个是目标状态。
输出
每组数据输出一个整数,占一行。
样例输入
21234 21441111 9999
样例输出
24
提示
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int st[6],goal[6];
char st0[6],goal0[6];
int visti[10000];
int ans;
struct data {
int s[6];
int sum;
};
//queue <data> que;
bool check(int s[])
{
int t=(s[0])*1000+(s[1])*100+(s[2])*10+(s[3]);
if(!visti[t]){
visti[t]=1;//标记为已访问
return true;
}
return false;
}
void bfs() {
queue <data> que;
data p;
memcpy(p.s,st,sizeof(st));
p.sum=0;
if(check(p.s))
que.push(p);
while(!que.empty()) {
p=que.front();
que.pop();
if(!memcmp(p.s,goal,sizeof(goal))) {
ans=p.sum;
return ;
}
for(int j=0; j<4; j++) {
int t=p.s[j];
p.sum++;
if(p.s[j]<9) p.s[j]++;
else p.s[j]=1;
if(check(p.s))
que.push(p);
p.s[j]=t;
if(p.s[j]>1) p.s[j]--;
else p.s[j]=9;
if(check(p.s))
que.push(p);
p.s[j]=t;
if(j<3) {
int temp;
temp=p.s[j+1];
p.s[j+1]=p.s[j];
p.s[j]=temp;
if(check(p.s))
que.push(p);
p.s[j]=t;
p.s[j+1]=temp;
}
p.sum--;
}
}
}
int main() {
int n;
scanf("%d",&n);
while(n--) {
ans=0;
scanf("%s%s",st0,goal0);
for(int i=0;i<4;i++)
{
st[i]=st0[i]-'0';
goal[i]=goal0[i]-'0';
}
memset(visti,0,sizeof(visti));
bfs();
printf("%d\n",ans);
}
}
下面的代码,想尝试用A*算法,写的,但是在求H(n)的函数那里找不到一个好的办法,所以导致超时了。留在这里日后思考。如果有路过的大神知道如何修改,可以私聊我。QQ:751479173
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int st[6],goal[6];
char st0[6],goal0[6];
int visti[10000];
int ans;
struct data {
int s[6];
int sum;
int g,h,f;
bool operator < (const data & k) const { //重载比较运算符
if(f==k.f)
return g>k.g;
return f > k.f;
}
};
//queue <data> que;
bool check(int s[]) {
int t=(s[0])*1000+(s[1])*100+(s[2])*10+(s[3]);
if(!visti[t]) {
visti[t]=1;//标记为已访问
return true;
}
return false;
}
int bianhao(int s[]) {
int t;
return t=(s[0])*1000+(s[1])*100+(s[2])*10+(s[3]);
}
int wrongPlaceNum(int a[]) { //求不在位的数字个数
int cnt=0;
for(int i=0; i<4; i++)
if(a[i]!=goal[i]) cnt++;
return cnt;
}
void bfs() {
priority_queue <data> que;
data p,q;
memcpy(q.s,st,sizeof(st));
q.sum=p.g=0;
q.h=wrongPlaceNum(q.s);
q.f=q.g+q.h;
if(check(q.s))
que.push(q);
while(!que.empty()) {
q=que.top();
que.pop();
if(!memcmp(q.s,goal,sizeof(goal))) {
ans=q.sum;
return ;
}
for(int j=0; j<4; j++) {
memcpy(&p,&q,sizeof(q));
if(p.s[j]<9) p.s[j]++;
else p.s[j]=1;
if(check(p.s)) {
p.g=p.g+1;
p.h=wrongPlaceNum(p.s);
p.f=p.g+p.h;
p.sum++;
que.push(p);
}
memcpy(&p,&q,sizeof(q));
if(p.s[j]>1) p.s[j]--;
else p.s[j]=9;
if(check(p.s)) {
p.g=p.g+1;
p.h=wrongPlaceNum(p.s);
p.f=p.g+p.h;
p.sum++;
que.push(p);
}
memcpy(&p,&q,sizeof(q));
if(j<3) {
int temp;
temp=p.s[j+1];
p.s[j+1]=p.s[j];
p.s[j]=temp;
if(check(p.s)) {
p.g=p.g+1;
p.h=wrongPlaceNum(p.s);
p.f=p.g+p.h;
p.sum++;
que.push(p);
}
}
memcpy(&p,&q,sizeof(q));
}
}
}
int main() {
int n;
scanf("%d",&n);
while(n--) {
ans=0;
scanf("%s%s",st0,goal0);
for(int i=0; i<4; i++) {
st[i]=st0[i]-'0';
goal[i]=goal0[i]-'0';
}
memset(visti,0,sizeof(visti));
bfs();
printf("%d\n",ans);
}
}