USACO: clocks

原创 2006年06月11日 13:38:00
这道题来自于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,所生成的数字一定大,故剪枝。

【数据结构】USACO clocks

最暴力的办法,开始超了。改了一些循环的控制就对了。 http://acm.sjtu.edu.cn/OnlineJudge/problem/1047 #include //clock //...
  • shen_bingyu
  • shen_bingyu
  • 2014年12月23日 18:14
  • 375

【USACO题库】1.4.2 The Clocks(搜索)

【USACO题库】1.4.2 The Clocks
  • fengyingjie2
  • fengyingjie2
  • 2016年05月15日 11:39
  • 230

一大堆的福利之【USACO题库】The Clocks

题目描述 考虑将如此安排在一个 3 x3 行列中的九个时钟: |-------| |-------| |-------| | | | | ...
  • sss_brs
  • sss_brs
  • 2017年03月29日 20:17
  • 113

USACO入门以及提交格式

从今天开始正式尝试usaco,刚注册了账号,发现验证码怎么都刷不出来,后来查了才知道是谷歌的验证码,被墙掉了,只能翻了墙才注册好 【usaco是美国中学生的官方竞赛网站,美国著名在线题库,专门为信息...
  • niskoy
  • niskoy
  • 2015年12月14日 21:52
  • 1638

USACO大量月赛题题解

为了准备NOIP,开始刷USACO了 搞来一本题典,100题不到,希望能把NOIP考点的相关题目都搞定 按照我的情况,简单题就不发了,容易上当的和难题会发上来...
  • qyl916
  • qyl916
  • 2013年10月15日 22:00
  • 4947

【最小生成树】【并查集】[USACO2016 金组]Fenced In

题目描述Farmer John has realized that many of his cows are strangely agoraphobic (being fearful of large...
  • JeremyGJY
  • JeremyGJY
  • 2016年03月12日 16:12
  • 677

USACO ariprog 暴力枚举+剪枝

/* ID:kevin_s1 PROG:ariprog LANG:C++ */ #include #include #include #include #include #include ...
  • Kevin_Samuel
  • Kevin_Samuel
  • 2014年06月03日 16:28
  • 1242

竞赛题目讲解 - 【USACO TRAINING】子集的和

【USACO TRAINING】子集的和 对于从1到N (1
  • C20192419MYS
  • C20192419MYS
  • 2017年06月11日 22:47
  • 373

【USACO4.4.2】追查坏牛奶(BSOI2140)

【USACO4.4.2】追查坏牛奶 Description   你第一天接手光明牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批坏牛奶。很不幸,你发...
  • hwzzyr
  • hwzzyr
  • 2017年02月20日 17:55
  • 270

【USACO2.1.5】海明码

显然是一个搜索题……但是我的方法好像偏了? 速度是还可以,但是代码长,占用内存多。 用邻接表的方式,来保存 i这个数字,到哪些数字的海明距离不到D的。  用链表的方式存储vis数组,...
  • baidu_23081367
  • baidu_23081367
  • 2015年02月03日 14:59
  • 387
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:USACO: clocks
举报原因:
原因补充:

(最多只允许输入30个字)