USACO: clocks

这道题来自于IOI 94。
Consider nine clocks arranged in a 3x3 array thusly:
|-------|    |-------|    |-------|    
| | | | | | |
|---O | |---O | | O |
| | | | | |
|-------| |-------| |-------|
A B C

|-------| |-------| |-------|
| | | | | |
| O | | O | | O |
| | | | | | | | |
|-------| |-------| |-------|
D E F

|-------| |-------| |-------|
| | | | | |
| O | | O---| | O |
| | | | | | | |
|-------| |-------| |-------|
G H I

The goal is to find a minimal sequence of moves to return all the dials to 12 o'clock. Nine different ways to turn the dials on the clocks are spplied via a table below; each way is called a move. Select for each move a number 1 through 9 which will cause the dials of the affected clocks (see next table) to be turned 90 degrees clockwise.

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

Example

Each number represents a time accoring to following table:
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

[But this might or might not be the `correct' answer; see below.]

PROGRAM NAME: clocks

INPUT FORMAT

Lines 1-3: Three lines of three space-separated numbers; each number represents the start time of one clock, 3, 6, 9, or 12. The ordering of the numbers corresponds to the first example above.

SAMPLE INPUT (file clocks.in)

9 9 12
6 6 6
6 3 6

OUTPUT FORMAT

A single line that contains a space separated list of the shortest sequence of moves (designated by numbers) which returns all the clocks to 12:00. If there is more than one solution, print the one which gives the lowest number when the moves are concatenated (e.g., 5 2 4 6 < 9 3 1 1).

SAMPLE OUTPUT (file clocks.out)

4 5 8 9

分析

这道目的一种解法是——穷举。每种移动方法最多出现3次,超过3次就无意义了。所以总共有4^9=2^18=256K种可能。基本上用穷举在很短的时间内就可以求出来了。
  1. 由于每种移动方法最多出现三次,故用一个32位整数就可以表示当前的移动方法(用9×3个bit)。
  2. 利用递归进行穷举的时候,可以剪枝来减小穷举的量。
代码:

#include <stdio.h>
#include <assert.h>

int rules[10][9] = { {0,0,0,0,0,0,0,0,0}, {3,3,0,3,3,0,0,0,0}, {3,3,3,0,0,0,0,0,0},
    {0,3,3,0,3,3,0,0,0}, {3,0,0,3,0,0,3,0,0}, {0,3,0,3,3,3,0,3,0},
    {0,0,3,0,0,3,0,0,3}, {0,0,0,3,3,0,3,3,0}, {0,0,0,0,0,0,3,3,3},
    {0,0,0,0,3,3,0,3,3}};

int getMinMoves(int clocks[9], int rule, int curMove);
void print(FILE* fout, int minMove);

int main(void)
{
    int clocks[9];
    int i;
    int min_moves;
    FILE* fin = fopen("clocks.in", "r");
    FILE* fout = fopen("clocks.out", "w");
    assert(fin != NULL && fout != NULL);
       
    for (i = 0; i < 9; i ++)
    {
        fscanf(fin, "%d", clocks+i);
        if (clocks[i] == 12)
        {
            clocks[i] = 0;//for arithmetic convenience
        }
    }

    min_moves = getMinMoves(clocks, 1, 0);

    print(fout, min_moves);
    fclose(fin);
    fclose(fout);
    return 0;
}

int getMinMoves(int clocks[9], int rule, int curMove)
{
    int tempMove = 0;//record the search result of the subtree
    int minMove = 1 << 29;//record the mini of search results, initially set to a big value
    int curClocks[9];//current clocks
    int i,j;
   
    memcpy(curClocks, clocks, sizeof(int)*9);
    for (i = 0; i < 4; i ++) // at most move 3 times according to curren rule
    {
        if ( i != 0)//if move clocks according to the current rule
        {
            curMove = curMove | (1 << ((rule -1)*3 + i - 1));
            for (j = 0; j < 9; j ++)
            {
                curClocks[j] = (clocks[j] + rules[rule][j] * i) % 12;
            }
        }

        for (j = 0; j < 9 && curClocks[j] == 0; j ++)
        {
        }
        if (j == 9)
        {
            return curMove;//if found in current rule, then update
        }

        if (rule < 9) // if not the last rule (9), then search the subtree
        {
            tempMove = getMinMoves(curClocks, rule + 1, curMove);
            if ((tempMove > 0) && (tempMove < minMove))
            {
                minMove = tempMove;
            }
        }
    }

    //if not results from the current search, then check the result from subtree
    if (rule == 9)
    {
        return 0;// last rule, so nothing found
    }
    else{
        if (minMove == (1 << 29))
        {
            return 0;// keep unchanged, nothing found
        }
        else{
            return minMove;
        }
    }
};

void print(FILE* fout, int minMove)
{
    int i = 0;
    int j = 1;
    int found = 0;
    do
    {
        if (j & minMove)
        {
            if (found)
            {
                fprintf(fout, " ");
            }
            fprintf(fout, "%d", i / 3 + 1);
            found = 1;
        }
        j = j << 1;
        i ++;
    } while (i < 27);
    fprintf(fout, "/n");
}

这个算法从第一种移动方法开始遍历至第9种移动方法以满足要求数字最小。唯一的剪枝发生在黑体字处,如果在遍历第n种做法的时候找到了合适的,则立即返回,因为这个必定是最小的。可以这样看,如果当前找到的数字是“xxxnn”,那么 首先可以排除有“xxx(n-1)”这样的数字,然后有的必然是“xxx(n+1)……”这样的字符串 ,假设现在需要k个n(1<=k<=3),那么要用其它的移动方法来代替k个n,其数量>=k。唯一相等的情况发生在某个移动方法和第n种方法完全一致的情况下。由于我是从第1种移动方法遍历到第9种,这样的话那个和第n种 移动方法一致的移动方法的序号一定>n,所生成的数字一定大,故剪枝。
购物商城项目采用PHP+mysql有以及html+css jq以及layer.js datatables bootstorap等插件等开发,采用了MVC模式,建立一个完善的电商系统,通过不同用户的不同需求,进行相应的调配和处理,提高对购买用户进行配置….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值