POJ1166Clocks(穷举+函数指针数组+位操作)

Description

这里写图片描述

There are nine clocks in a 3*3 array (figure 1). The goal is to return all the dials to 12 o’clock with as few moves as possible. There are nine different allowed ways to turn the dials on the clocks. Each such way is called a move. Select for each move a number 1 to 9. That number will turn the dials 90’ (degrees) clockwise on those clocks which are affected according to figure 2 below.
Move Affected clocks

1 ABDE

2 ABC

3 BCEF

4 ADG

5 BDEFH

6 CFI

7 DEGH

8 GHI

9 EFHI

(Figure 2)

Input

Your program is to read from standard input. Nine numbers give the start positions of the dials. 0=12 o’clock, 1=3 o’clock, 2=6 o’clock, 3=9 o’clock.

Output

Your program is to write to standard output. Output a shortest sorted sequence of moves (numbers), which returns all the dials to 12 o’clock. You are convinced that the answer is unique.

Sample Input

3 3 0
2 2 2
2 1 2

Sample Output

4 5 8 9

算法

穷举,穷举对象和前几篇文章POJ1222,1753不同,穷举不同的操作的操作次数(每个操作最多3次,否则与之前相同),这一方面是因为题目缺少一个可以确定全部操作的局部(POJ1222里的第一行或第一列),另一方面对一个数据可进行的操作的种数过多,难以穷举对单个数据的操作。
POJ1222题解,(看一个就够,1753换汤不换药)
然后就是比较,更新最小值,输出等等。

Trick

对不同的操作的操作数进行穷举,很多网上的题解采用了九重循环的方式,不太雅观,可以使用位操作替代,也就是一个数中的特定位置的几个bit位代表某个操作的操作次数,本题中操作数量最多为3,可用两个bit位表示,比如代码中的k最后两个bit表示OpeA的操作数量,倒数3-4的表示OpeB的操作数量,以此类推,同时九个操作函数可以使用函数指针数组的方式存储,方便快捷!

AC Code

#include<stdio.h>

#define NUMOPE 9

int GetBit(int Target, int i);
//The times of one operation from bits
void OpeA(int Present[3][3]);
void OpeB(int Present[3][3]);
void OpeC(int Present[3][3]);
void OpeD(int Present[3][3]);
void OpeE(int Present[3][3]);
void OpeF(int Present[3][3]);
void OpeG(int Present[3][3]);
void OpeH(int Present[3][3]);
void OpeI(int Present[3][3]);
//All the operations
int Test(int Present[3][3]);
int Compute(int k);
//How many operations are there?
void DisplayOpe(int k);
void GetOrigin(int Origin[][3]);

int main()
{
    void (*Operate[NUMOPE + 2])(int Present[3][3]) = {
            OpeA, OpeB, OpeC, OpeD, OpeE, OpeF, OpeG, OpeH, OpeI
    };                                  //function pointer array
    int Origin[3][3], Present[3][3], min = 50, minOpe = 0;
    int OpeNum[9];

    GetOrigin(Origin);
    for (int k = 0; k < 262144; k++) {                  //all the combinations of operation in bits
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Present[i][j] = Origin[i][j];
            }
        }

        for (int i = 0; i < 9; i++) {
            int num = GetBit(k,i);
            if (num) {
                for (int ii = 0; ii < num; ii++) {
                    Operate[i](Present);
                }
            }
        }

        if (Test(Present)) {
            int Total = Compute(k);
            if (Total < min) {
                min = Total;
                minOpe = k;
            }
        }
    }

    //printf("%d\n", min);
    DisplayOpe(minOpe);

    return 0;
}

void GetOrigin(int Origin[][3])
{
    for (int  i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            scanf("%d", &Origin[i][j]);
        }
    }
}

int GetBit(int Target, int i)
{
     return ((Target >> (2 * i)) & 1) + ((Target >> (2 * i + 1)) & 1) * 2;
}

void OpeA(int Present[3][3])
{
    Present[0][0] = (Present[0][0] + 1) % 4;
    Present[0][1] = (Present[0][1] + 1) % 4;
    Present[1][0] = (Present[1][0] + 1) % 4;
    Present[1][1] = (Present[1][1] + 1) % 4;
}

void OpeB(int Present[3][3])
{
    Present[0][0] = (Present[0][0] + 1) % 4;
    Present[0][1] = (Present[0][1] + 1) % 4;
    Present[0][2] = (Present[0][2] + 1) % 4;
}

void OpeC(int Present[3][3])
{
    Present[0][1] = (Present[0][1] + 1) % 4;
    Present[0][2] = (Present[0][2] + 1) % 4;
    Present[1][1] = (Present[1][1] + 1) % 4;
    Present[1][2] = (Present[1][2] + 1) % 4;
}

void OpeD(int Present[3][3])
{
    Present[0][0] = (Present[0][0] + 1) % 4;
    Present[1][0] = (Present[1][0] + 1) % 4;
    Present[2][0] = (Present[2][0] + 1) % 4;
}

void OpeE(int Present[3][3])
{
    Present[1][0] = (Present[1][0] + 1) % 4;
    Present[1][1] = (Present[1][1] + 1) % 4;
    Present[1][2] = (Present[1][2] + 1) % 4;
    Present[2][1] = (Present[2][1] + 1) % 4;
    Present[0][1] = (Present[0][1] + 1) % 4;
}

void OpeF(int Present[3][3])
{
    Present[0][2] = (Present[0][2] + 1) % 4;
    Present[1][2] = (Present[1][2] + 1) % 4;
    Present[2][2] = (Present[2][2] + 1) % 4;
}

void OpeG(int Present[3][3])
{
    Present[1][0] = (Present[1][0] + 1) % 4;
    Present[1][1] = (Present[1][1] + 1) % 4;
    Present[2][0] = (Present[2][0] + 1) % 4;
    Present[2][1] = (Present[2][1] + 1) % 4;
}

void OpeH(int Present[3][3])
{
    Present[2][0] = (Present[2][0] + 1) % 4;
    Present[2][1] = (Present[2][1] + 1) % 4;
    Present[2][2] = (Present[2][2] + 1) % 4;
}

void OpeI(int Present[3][3])
{
    Present[1][1] = (Present[1][1] + 1) % 4;
    Present[1][2] = (Present[1][2] + 1) % 4;
    Present[2][1] = (Present[2][1] + 1) % 4;
    Present[2][2] = (Present[2][2] + 1) % 4;
}

int Test(int Present[3][3])
{
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (Present[i][j] != 0) {
                return 0;
            }
        }
    }

    return 1;
}

int Compute(int k) {
    int Total = 0;
    for (int i = 0; i < 9; i++) {
        Total += GetBit(k, i);
    }
    return Total;
}

void DisplayOpe(int k)
{
    int Bool = 1;
    for (int i = 0; i < 9; i++) {
        int num = GetBit(k,i);
        if (num) {
            if (Bool) {
                Bool = 0;
                printf("%d", i + 1);
                for (int ii = 0; ii < num - 1; ii++) {
                    printf(" %d", i + 1);
                }
            }
            else {
                for (int ii = 0; ii < num; ii++) {
                    printf(" %d", i + 1);
                }
            }
        }
    }
    printf("\n");
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值