题目描述
考虑将如此安排在一个 3 x3 行列中的九个时钟:
|-------| |-------| |-------|
| | | | | | |
|---O | |---O | | O |
| | | | | |
|-------| |-------| |-------|
A B C
|-------| |-------| |-------|
| | | | | |
| O | | O | | O |
| | | | | | | | |
|-------| |-------| |-------|
D E F
|-------| |-------| |-------|
| | | | | |
| O | | O---| | O |
| | | | | | | |
|-------| |-------| |-------|
G H I目标要找一个最小的移动顺序次将所有的指针指向12点。下面原表格列出了9种不同的旋转指针的方法,每一种方法都叫一次移动。选择1到9号移动方法,将会使在表格中对应的时钟的指针顺时针旋转90度。
移动方法 受影响的时钟 1 ABDE 2 ABC 3 BCEF 4 ADG 5 BDEFH 6 CFI 7 DEGH 8 GHI 9 EFHI Example 9 9 12 9 12 12 9 12 12 12 12 12 12 12 12 6 6 6 5 -> 9 9 9 8-> 9 9 9 4 -> 12 9 9 9-> 12 12 12 6 3 6 6 6 6 9 9 9 12 9 9 12 12 12
[但这可能不是正确的方法,请看下面]
输入
第1-3行: 三个空格分开的数字,每个数字表示一个时钟的初始时间,3,6,9,12。数字的含意和上面第一个例子一样。
输出
单独的一行包括一个用空格分开的将所有指针指向12:00的最短移动顺序的列表。 如果有多种方案,输出那种使的连接起来数字最小的方案。(举例来说5 2 4 6 < 9 3 1 1)。
样例输入
9 9 12
6 6 6
6 3 6样例输出
4 5 8 9提示
思路:很明显的BFS,用ans数组记录一下方法,用pre数组记录一下到当前点的路径,判断某个状态是否已经出现过,即vis过,转化成4进制的9位数,因为只有4种状态,则可用数组存下了。最后递归输出就好了。
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
using namespace std;
#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)
const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const int N = 1e7+5;
int vis[N];
int b[10];
int pre[N];
int ans[N];
int res;
int dir[10][10]={
0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,0,0,0,0,
0,1,1,1,0,0,0,0,0,0,
0,0,1,1,0,1,1,0,0,0,
0,1,0,0,1,0,0,1,0,0,
0,0,1,0,1,1,1,0,1,0,
0,0,0,1,0,0,1,0,0,1,
0,0,0,0,1,1,0,1,1,0,
0,0,0,0,0,0,0,1,1,1,
0,0,0,0,0,1,1,0,1,1
};
int cal(int a[])
{
int sum=0;
int tmp=1;
for(int i=1;i<=9;i++)
{
sum+=a[i]*tmp;
tmp*=4;
}
return sum;
}
struct node
{
int a[10];
int idx; //索引
};
void bfs()
{
queue<node>q;
node now,next;
MEM(vis,0);
int x=cal(b);
vis[x]=1;
for(int i=1;i<=9;i++)
now.a[i]=b[i];
int cnt=0;
now.idx=0;
pre[now.idx]=-1;
q.push(now);
while(!q.empty())
{
now=q.front();
q.pop();
bool flag=true;
for(int i=1;i<=9;i++)
if(now.a[i]!=3)
flag=false;
if(flag)
{
res=now.idx;
return;
}
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
next.a[j]=(now.a[j]+dir[i][j])%4;
int tmp=cal(next.a);
if(!vis[tmp])
{
cnt++;
vis[tmp]=1;
next.idx=cnt;
pre[next.idx]=now.idx;
ans[next.idx]=i;
q.push(next);
}
}
}
}
void output(int xx)
{
if(pre[xx]==-1)
{
return ;
}
output(pre[xx]);
printf("%d ",ans[xx]);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
std::ios::sync_with_stdio(false);
int n;
while(~scanf("%d",&b[1]))
{
for(int i=2;i<=9;i++)
scanf("%d",&b[i]);
bool flag=true;
for(int i=1;i<=9;i++)
{
b[i]=b[i]/3-1;
if(b[i]!=3)
flag=false;
}
if(flag)
{
printf("\n");
continue;
}
bfs();
output(pre[res]);
printf("%d\n",ans[res]);
}
return 0;
}

本文介绍了一个经典的3x3时钟谜题,通过最少步骤将所有时钟指针指向12点。使用广度优先搜索(BFS)算法进行求解,并详细展示了从输入到输出的完整流程。
&spm=1001.2101.3001.5002&articleId=79704591&d=1&t=3&u=1f2af33dbb4f480dbd2bd926ab7ecccd)
614

被折叠的 条评论
为什么被折叠?



