問題 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);
}
}