Openjudge2814:拨钟问题

题目:

拨钟问题

有9个时钟,排成一个3*3的矩阵。

现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。

这里写图片描述

移动    影响的时钟

 1         ABDE
 2         ABC
 3         BCEF
 4         ADG
 5         BDEFH
 6         CFI
 7         DEGH
 8         GHI
 9         EFHI 

Input
9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。
Output
输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。
Sample Input
3 3 0
2 2 2
2 1 2
Sample Output
4 5 8 9

题意:
有9个钟,每个钟初始只能为0, 1, 2, 3, 其中0代表12点, 1代表3点, 2代表6点, 3代表9点。
有9个操作,每个操作将操作中对应序号的时钟顺时针旋转90度,问题是找出一个操作最少的组合,使得所有的时钟都变为12点。

思路:
对于列表中1到9的某一个操作,可以进行0次、1次、2次、3次,第4次就变回本身。那么一共有4^9次方个组合。可以用9个for循环,也可以用dfs。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
int arr[10];
int vis[10];
int sum[10];
int ans[10];
int minn=0x7FFFFFFF;

using namespace std;
char mp[15][15] ={
    "",
    "ABDE",
    "ABC",
    "BCEF",
    "ADG",
    "BDEFH",
    "CFI",
    "DEGH",
    "GHI",
    "EFHI"
};

void dfs(int depth){
    if(depth==10){
        for(int i=1; i<=9; i++){
            if(arr[i]%4!=0){  
                return;
            }
        }
        int asum = 0;
        for(int i=1; i<=9; i++){
            asum += sum[i];
        }

        if(asum<minn){
            for(int i=1; i<=9; i++){
                if(vis[i]==1){
                    ans[i] = sum[i];
                }
                else
                    ans[i]=0;
            }
            minn = asum;
        }
        return;
    }
    for(int i=0; i<4; i++){
        for(int j=0; j<strlen(mp[depth]); j++){
           // arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]+3*i)%12;
            arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]+i);
        }
        vis[depth]=(i==0)?0:1;
        sum[depth]=i;

        dfs(depth+1);

        for(int j=0; j<strlen(mp[depth]); j++){
            //arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]+12*i-3*i)%12;
            arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]-i);
        }
        vis[depth]=0;
        sum[depth]=0;
    }
}

int main(){
    int tmp;
    memset(arr, 0, sizeof(arr));
    //freopen("input.txt","r", stdin);
    //freopen("output.txt", "w", stdout);
    for(int i=1; i<=9; i++){
        cin>>tmp;
        arr[i] = tmp;
    }

    dfs(1);

    int tag=0;
    for(int i=1; i<=9; i++){
        if(ans[i]!=0){
            for(int j=0; j<ans[i]; j++){
                if(tag==0){cout<<i; tag=-1;}
                else cout<<" "<<i;
            }
        }
    }
    cout<<endl;
    return 0;
}

总结:

题意又理解偏了,(汗!--)
输入只可能为0, 1, 2, 3,我以为还有其他的输入。。于是我将0, 1, 2 , 3转化为所对应的实际的点,按理说这样模拟也可以过,但是开始忘记将minn的值进行更新,改了之后还是WA,卡了一个下午,最后问了一下同学,发现又将题意理解错了,于是我按输入只有0, 1, 2, 3来写,过了。我倒回头看原来模拟的写法,漏了指令使用次数为0时的一次模运算!!!

下面贴最开始模拟现实时钟的写法(看错题目的产物):

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
int arr[10];
int vis[10];
int sum[10];
int ans[10];
int minn=0x7FFFFFFF;

using namespace std;
char mp[15][15] ={
    "",
    "ABDE",
    "ABC",
    "BCEF",
    "ADG",
    "BDEFH",
    "CFI",
    "DEGH",
    "GHI",
    "EFHI"
};

void dfs(int depth){
    if(depth==10){
        for(int i=1; i<=9; i++){
            if(arr[i]!=0){
                return;
            }
        }
        //for(int i=1; i<=9; i++) {cout<<arr[i]<<" "; cout<<endl;}
        int asum = 0;
        for(int i=1; i<=9; i++){
            asum += sum[i];
        }

        if(asum<minn){
            for(int i=1; i<=9; i++){
                if(vis[i]==1){
                    ans[i] = sum[i];
                }
                else
                    ans[i]=0;
            }
            minn = asum;
        }
        return;
    }
    for(int i=0; i<4; i++){
        for(int j=0; j<strlen(mp[depth]); j++){
            arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]+3*i)%12;
        }
        vis[depth]=(i==0)?0:1;
        sum[depth]=i;

        dfs(depth+1);

        for(int j=0; j<strlen(mp[depth]); j++){
            arr[mp[depth][j]-64] = (arr[mp[depth][j]-64]+12*i-3*i)%12;
        }
        vis[depth]=0;
        sum[depth]=0;
    }
}

int main(){
    int tmp;
    memset(arr, 0, sizeof(arr));
    //freopen("input.txt","r", stdin);
    //freopen("output.txt", "w", stdout);
    for(int i=1; i<=9; i++){
        cin>>tmp;
        if(tmp==0) arr[i]=12;
        else if(tmp==1) arr[i]=3;
        else if(tmp==2) arr[i]=6;
        else if(tmp==3) arr[i]=9;
        // else if(tmp==4) arr[i]=12;
        // else if(tmp==5) arr[i]=3;
        // else if(tmp==6) arr[i]=6;
        // else if(tmp==7) arr[i]=9;
        // else if(tmp==8) arr[i]=12;
        // else if(tmp==9) arr[i]=3;
        // else if(tmp==10) arr[i]=6;
        // else if(tmp==11) arr[i]=9;
        // else arr[i]=12;
    }

    dfs(1);

    int tag=0;
    for(int i=1; i<=9; i++){
        if(ans[i]!=0){
            for(int j=0; j<ans[i]; j++){
                if(tag==0){cout<<i; tag=-1;}
                else cout<<" "<<i;
            }
        }
    }
    cout<<endl;
    return 0;
}

写了这题收获很多!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值