ITON - 1 论矩阵的妙用

关于标题

I(Interesting)T(Test)O(Of)N(Noip)


番外(论矩阵的妙用)

一道USACO的题:

The Clocks【搜索专题】

题目背景
USACO 1.4.2 (IOI’94)
搜索专题训练(一)

题目描述
考虑将如此安排在一个 3×3 行列中的九个时钟:

这里写图片描述

目标要找一个最小的移动顺序次将所有的指针指向12点.
下面原表格列出了 9 种不同的旋转指针的方法,每一种方法都叫一次移动。
选择 1 到 9 号移动方法,将会使在表格中对应的时钟的指针顺时针旋转90度。

移动方法 —– 受影响的时钟
— 1 ————— ABDE —–
— 2 ————— ABC ——
— 3 ————— BCEF ——
— 4 ————— ADG ——
— 5 ————– BDEFH —–
— 6 ————— CFI ——–
— 7 ————— DEGH —–
— 8 ————— GHI ——–
— 9 ————— EFHI ——–
比如一个例子:

这里写图片描述

但这可能不是正确的方法,请看下面。

输入格式
第 1-3 行:三个空格分开的数字,每个数字表示一个时钟的初始时间:3,6,9,12。
数字的含意和上面第一个例子一样。

输出格式
单独的一行包括一个用空格分开的将所有指针指向 12:00 的最短移动顺序的列表。
如果有多种方案,输出那种使的连接起来数字最小的方案。(举例来说:5 2 4 6 < 9 3 1 1)。

样例数据 1
输入  [复制]

9 9 12
6 6 6
6 3 6
输出

4 5 8 9
这是我同学SZM的代码:

SZM.CPP

#include<bits/stdc++.h>
using namespace std;

int f[500005][4][4],num[4][4],done[500005],pre[500005];
int head,tail,ans=0;
bool p[4][4][4][4][4][4][4][4][4];
bool flag=false;

inline int add(int x)
{
    x=x+1;
    if(x==4) return 0;
    else return x;
}

inline void work1(int x)
{
    int a[4][4];

    for(int t=1;t<=3;++t)
    {
        for(int h=1;h<=3;++h)
        {
            a[t][h]=f[x][t][h];
        }
    }

    a[1][1]=add(a[1][1]);
    a[1][2]=add(a[1][2]);
    a[2][1]=add(a[2][1]);
    a[2][2]=add(a[2][2]);

    bool fuck=true;

    for(int t=1;t<=3;++t)
    {
        for(int h=1;h<=3;++h)
        {
            if(a[t][h]!=3)
            {
                fuck=false;
                break;
            }
        }
        if(fuck==false) break;
    }
    if(fuck==true)
    {
        int now=x,q[22],val=0;
        flag=true;
        q[++val]=1;

        if(x!=1)    q[++val]=done[x];

        while(pre[now]!=0)
        {
            now=pre[now];
            if(done[now]!=0)
            {
                q[++val]=done[now];
            }
        }

        for(int t=val;t>=1;--t) 
            cout<<q[t]<<' ';
    }

    if(!p[a[1][1]][a[1][2]][a[1][3]][a[2][1]][a[2][2]][a[2][3]][a[3][1]][a[3][2]][a[3][3]])
    {
        p[a[1][1]][a[1][2]][a[1][3]][a[2][1]][a[2][2]][a[2][3]][a[3][1]][a[3][2]][a[3][3]]=true;

        ++tail;
        for(int t=1;t<=3;++t)
        {
            for(int h=1;h<=3;++h)
            {
                f[tail][t][h]=a[t][h];
                if(a[t][h]>3) ans++;
            }
        }
        pre[tail]=x,done[tail]=1;
    }
}
inline void work2(int x)
{
    int a[4][4];
    for(int t=1;t<=3;++t)
    {
        for(int h=1;h<=3;++h)
        {
            a[t][h]=f[x][t][h];
        }
    }

    a[1][1]=add(a[1][1]);
    a[1][2]=add(a[1][2]);
    a[1][3]=add(a[1][3]);

    bool fuck=true;

    for(int t=1;t<=3;++t)
    {
        for(int h=1;h<=3;++h)
        {
            if(a[t][h]!=3)
            {
                fuck=false;
                break;
            }
        }
        if(fuck==false) break;
    }
    if(fuck==true)
    {
        int now=x,q[22],val=0;
        flag=true;
        q[++val]=2;
        if(x!=1)q[++val]=done[x];
        while(pre[now]!=0)
        {
            now=pre[now];
            if(done[now]!=0)
            {
                q[++val]=done[now];
            }
        }
        for(int t=val;t>=1;t--) cout<<q[t]<<' ';
    }
    if(!p[a[1][1]][a[1][2]][a[1][3]][a[2][1]][a[2][2]][a[2][3]][a[3][1]][a[3][2]][a[3][3]])
    {
        p[a[1][1]][a[1][2]][a[1][3]][a[2][1]][a[2][2]][a[2][3]][a[3][1]][a[3][2]][a[3][3]]=true;

        tail++;
        for(int t=1;t<=3;++t)
        {
            for(int h=
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值