【USACO 1.4.2】时钟
【题目描述】
考虑将如此安排在一个 3 x 3 行列中的九个时钟:
|-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C
|-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |-------| D E F
|-------| |-------| |-------| | | | | | | | O | | O---| | O | | | | | | | | | |-------| |-------| |-------| G H I
目标要找一个最小的移动顺序将所有的指针指向12点。下面原表格列出了9种不同的旋转指针的方法,每一种方法都叫一次移动。选择1到9号移动方法,将会使在表格中对应的时钟的指针顺时针旋转90度。
移动方法 受影响的时钟 1 ABDE 2 ABC 3 BCEF 4 ADG 5 BDEFH 6 CFI 7 DEGH 8 GHI 9 EFHI
Example
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 [但这可能不是正确的方法,请看下面]
【格式】
INPUT FORMAT:
(file clocks.in)
第1-3行: 三个空格分开的数字,每个数字表示一个时钟的初始时间,3,6,9,12。数字的含意和上面第一个例子一样。
OUTPUT FORMAT:
(file clocks.out)
单独的一行包括一个用空格分开的将所有指针指向12:00的最短移动顺序的列表。
如果有多种方案,输出那种使其连接起来数字最小的方案。(举例来说5 2 4 6 < 9 3 1 1)。
【分析】
好吧,我偷懒了......用了9重循环的方法。
九重循环的方法大家都会,不解释了,实际上,网上流传有一种很好的方法可以在很短的时间内解决。
如下:
首先可以求出一个数组cnt[i][j],表示第i个钟转到12点需要使用方法j共cnt[i][j]次。
eg.只将第一个钟转90度,那么需要使用方法一3次、方法二3次、方法三3次、……、方法九0次(即{3,3,3,3,3,2,3,2,0})
于是,只需要知道每个钟要转几次,再mod 4(同一种方法使用4次,等于没转),就能得出答案。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 const int maxn=10000; 7 using namespace std; 8 struct Clock 9 { 10 int clock[15]; 11 }data,now; 12 int mz[15],ans[maxn*2],rem[maxn*2]; 13 int change[15][15]= 14 { 15 {0,3,3,0,3,3,0,0,0,0}, 16 {0,3,3,3,0,0,0,0,0,0}, 17 {0,0,3,3,0,3,3,0,0,0}, 18 {0,3,0,0,3,0,0,3,0,0}, 19 {0,0,3,0,3,3,3,0,3,0}, 20 {0,0,0,3,0,0,3,0,0,3}, 21 {0,0,0,0,3,3,0,3,3,0}, 22 {0,0,0,0,0,0,0,3,3,3}, 23 {0,0,0,0,0,3,3,0,3,3}, 24 }; 25 inline int MOD(int num) {return num%12==0?12:num%12;} 26 27 int main() 28 { 29 int i,j,k; 30 //文件操作 31 freopen("clocks.in","r",stdin); 32 freopen("clocks.out","w",stdout); 33 for (i=1;i<=9;i++) scanf("%d",&data.clock[i]); 34 35 ans[0]=0x7fffffff; 36 //枚舉 37 for (mz[0]=0;mz[0]<4;mz[0]++) 38 for (mz[1]=0;mz[1]<4;mz[1]++) 39 for (mz[2]=0;mz[2]<4;mz[2]++) 40 for (mz[3]=0;mz[3]<4;mz[3]++) 41 for (mz[4]=0;mz[4]<4;mz[4]++) 42 for (mz[5]=0;mz[5]<4;mz[5]++) 43 for (mz[6]=0;mz[6]<4;mz[6]++) 44 for (mz[7]=0;mz[7]<4;mz[7]++) 45 for (mz[8]=0;mz[8]<4;mz[8]++) 46 { 47 int lj=0,point=0,flag=1; 48 for (i=0;i<=8;i++) lj+=mz[i]; 49 if (lj>ans[0]) continue;//跳过 50 51 now=data; 52 //逐位提取 53 for (i=0;i<=8;i++) 54 for (j=1;j<=mz[i];j++) 55 { 56 for (k=1;k<=9;k++) 57 now.clock[k]=MOD(now.clock[k]+change[i][k]); 58 } 59 60 //判断是否满足条件 61 for (i=1;i<=9;i++) if (now.clock[i]!=12) {flag=0;break;} 62 if (flag==0) continue; 63 64 //构造解 65 for (i=0;i<=8;i++) 66 for (j=1;j<=mz[i];j++) rem[++point]=i; 67 68 if (lj==ans[0]) 69 { 70 for (i=1;i<=ans[0];i++) 71 if (rem[i]>ans[i]) {flag=0;break;} 72 } 73 if (flag==0) continue; 74 ans[0]=lj; 75 for (i=1;i<=ans[0];i++) ans[i]=rem[i]; 76 77 } 78 for (i=1;i<=ans[0];i++) printf("%d ",ans[i]+1); 79 return 0; 80 }