【USACO】时钟(BFS)

题目描述

考虑将如此安排在一个 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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值