【题目描述】
考虑将如此安排在一个 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次,等于没转),就能得出答案。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
const int maxn=;
using namespace std;
struct Clock
{
int clock[];
}data,now;
int mz[],ans[maxn*],rem[maxn*];
int change[][]=
{
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
{,,,,,,,,,},
};
inline int MOD(int num) {return num%==?:num%;} int main()
{
int i,j,k;
//文件操作
freopen("clocks.in","r",stdin);
freopen("clocks.out","w",stdout);
for (i=;i<=;i++) scanf("%d",&data.clock[i]); ans[]=0x7fffffff;
//枚舉
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
for (mz[]=;mz[]<;mz[]++)
{
int lj=,point=,flag=;
for (i=;i<=;i++) lj+=mz[i];
if (lj>ans[]) continue;//跳过 now=data;
//逐位提取
for (i=;i<=;i++)
for (j=;j<=mz[i];j++)
{
for (k=;k<=;k++)
now.clock[k]=MOD(now.clock[k]+change[i][k]);
} //判断是否满足条件
for (i=;i<=;i++) if (now.clock[i]!=) {flag=;break;}
if (flag==) continue; //构造解
for (i=;i<=;i++)
for (j=;j<=mz[i];j++) rem[++point]=i; if (lj==ans[])
{
for (i=;i<=ans[];i++)
if (rem[i]>ans[i]) {flag=;break;}
}
if (flag==) continue;
ans[]=lj;
for (i=;i<=ans[];i++) ans[i]=rem[i]; }
for (i=;i<=ans[];i++) printf("%d ",ans[i]+);
return ;
}