USACO:1.4.2 The Clocks 时钟(IOI 94) 解析

来源:互联网 发布:约瑟夫环c语言 编辑:程序博客网 时间:2024/06/05 10:49

USACO:1.4.2 The Clocks 时钟(IOI 94) 解析

IOI'94 - Day 2

题目描述:

考虑将如此安排在一个3X3 行列中的九个时钟:

|-------|    |-------|    |-------|    |       |    |       |    |   |   |    |---O   |    |---O   |    |   O   |          |       |    |       |    |       |           |-------|    |-------|    |-------|        A            B            C|-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O   |    |   O   ||   |   |    |   |   |    |   |   ||-------|    |-------|    |-------|    D            E            F|-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O---|    |   O   ||   |   |    |       |    |   |   ||-------|    |-------|    |-------|    G            H            I

目标要找一个最小的移动顺序次将所有的指针指向12 点。

       下面原表格列出了9 种不同的旋转指针的方法,每一种方法都叫一次移动。选择1 到9 号移动方法,将会使在表格中对应的时钟的指针顺时针旋转90 度。

移动方法 受影响的时钟

MoveAffected clocks1ABDE2ABC3BCEF4ADG5BDEFH6CFI7DEGH8GHI9EFHI例如:

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 
[但这可能不是正确的方法,请看下面]
PROGRAM NAME:clocks
INPUT FORMAT:
第1-3 行: 三个空格分开的数字,每个数字表示一个时钟的初始时间,3,6,9,12。数字的含意和上面第一个例子一样。
SAMPLE INPUT (file clocks.in)
9 9 12
6 6 6
6 3 6
OUTPUT FORMAT:
单独的一行包括一个用空格分开的将所有指针指向12:00 的最短移动顺序的列表。如果有多种方案,输出那种使的连接起来数字最小的方案。(举例来说5 2 4 6 < 9 3 1 1)。
SAMPLE OUTPUT (file clocks.out)

4 5 8 9

解题思路:

       首先得承认,这个简单的题我也没做出来,辜负了大家的期待。。。但)必须向前看:敢于面对挫折和失败,不断尝试,积累知识,厚积薄发!

在这里,我解读一下USACO的源码思路:

       做题之前,我们先看清题意,做简单的分析:我们可以发现两点,1、每个时钟是有周期的,最多移动3次(因为钟指针的周期性);2、输出格式中明确要求,“最短移动顺序”和“连接起来数字最小”,即为移动次数最小且移动方法的(可重复)字典序最小。基于此,我们可以设计一个1-9(方法)的递归,同时每第n次递归中尝试rep重复 3到0次方法n,先rep 3次保证字典序最小(次数相等时)。

/* Notice that the order in which we apply moves is irrelevant, and that applying a move four times is the same as applying it not at all.Thus there are only 49 = 262144 move sequences that need to be tried, so we might as well just try them all.We don't generate them shortest first,but looking at sequences of the same length, we generate the lesser ones before the greater ones, so we only need to keep track of the shortest working sequence we've found.*/

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <ctype.h>#define INF 60000// bigger than longest possible path ???char  * movestr[] = { "abde", "abc", "bcef", "adg", "bdefh", "cfi", "degh",//???                    "ghi", "efhi" };//表中内容int movedist[9][9];//表对应矩阵;int clock[9];int bestmove[9];//flag 标志表中1-9操作的次数;int nbestmove;/* translate move strings into array "movedist" of which clocks change on each move */voidmkmove(void){    int i;    char *p;    for(i=0; i<9; i++)for(p=movestr[i]; *p; p++)    movedist[i][*p-'a'] = 3;//翻译成9x9的}/* apply some number of each move from k to 9 ,move contains the number of times each move is applied *///move中临时存数据move[i]为表中第i操作的次数voidsolve(int *move, int k){    int i, j, n, rep;    if(k == 9) {       //???for(j=0; j<9; j++)    if(clock[j]%12 != 0)return;/* we have a successful sequence of moves */n = 0;for(j=0; j<9; j++)    n += move[j];if(nbestmove == 0 || n < nbestmove) {    nbestmove = n;    for(j=0; j<9; j++)bestmove[j] = move[j];}return;    }/* the for loop counts down so we generate smaller numbers first bytrying more of small numbered moves before we try less of them.???     */    for(rep=3; rep>=0; rep--) {/* apply move k rep times *///每个最多移动4次for(i=0; i<rep; i++)    for(j=0; j<9; j++)clock[j] += movedist[k][j];//完成第k种移动move[k] = rep;//solve(move, k+1);/* undo move */ //恢复移动前状态for(i=0; i<rep; i++)    for(j=0; j<9; j++)clock[j] -= movedist[k][j];    }}voidmain(void){    FILE *fin, *fout;    int i, j, move[9];    char *sep;// 字符指针 c-串    fin = fopen("clocks.in", "r");    fout = fopen("clocks.out", "w");    assert(fin != NULL && fout != NULL);    mkmove();//翻译表     for(i=0; i<9; i++)fscanf(fin, "%d", &clock[i]);    solve(move, 0);    sep = "";//    for(i=0; i<9; i++) {     //???for(j=0; j<bestmove[i]; j++) {    fprintf(fout, "%s%d", sep, i+1);sep = " ";}    }    fprintf(fout, "\n");    exit(0);}

         原码引自USACO,请原谅我造次引用和解读你们的代码!

       由于自身是初学者,编程能力有限,未达到程序员的水平原因,可能误导大家,请大家甄读;文字编辑一般,文中会有言辞不当。博文中的错误和不足敬请读者批评指正。    

0 0
原创粉丝点击