1816:拨钟问题
-
总时间限制:
- 1000ms 内存限制:
- 65536kB
-
描述
-
有9个时钟,排成一个3*3的矩阵。
|-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |-------| D E F |-------| |-------| |-------| | | | | | | | O | | O---| | O | | | | | | | | | |-------| |-------| |-------| G H I (图 1)
现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。
移动 影响的时钟 1 ABDE 2 ABC 3 BCEF 4 ADG 5 BDEFH 6 CFI 7 DEGH 8 GHI 9 EFHI
输入
- 9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。 输出
- 输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。 样例输入
-
3 3 0 2 2 2 2 1 2
样例输出
-
4 5 8 9
来源
- 1166
-
- #------------------------------------------------------------------------------#
- openjudge版诈尸~被尘封的openjudge……
-
- 显然,看到此题的标题——枚举,我们都知道要怎么做。
- 题目上的“移动”透露了一切,几乎和“移动”有关的,第一就是搜索,第二就是动规。
- 这道题我当然选择用枚举——搜索。
-
- 深度优先搜索思路:
- 显然一个钟,转4次就相当于没转,所以枚举:转0次,1次,2次和3次,每个钟有9种转法(尽管不是每种都会影响这个种),有九种钟。我们可以用一个常量数组保存。再深搜转的顺序和次数,保存一下即可。
-
- 粗略计算一下深搜时间复杂度:O((4^9)*9*9),才21233664,没有任何毛病。
-
- 代码:
-
#include<cstdio> #include<cstdlib> #define MAXN 9 int clocks[MAXN+5],ans[MAXN+5];//ans存每个转法转的次数 const int f[MAXN+5][MAXN+5]= { {0}, {0,1,1,0,1,1,0,0,0,0}, {0,1,1,1,0,0,0,0,0,0}, {0,0,1,1,0,1,1,0,0,0}, {0,1,0,0,1,0,0,1,0,0}, {0,0,1,0,1,1,1,0,1,0}, {0,0,0,1,0,0,1,0,0,1}, {0,0,0,0,1,1,0,1,1,0}, {0,0,0,0,0,0,0,1,1,1}, {0,0,0,0,0,1,1,0,1,1}, };//常量数组,f[i][j]表示第i种转法第j个钟是否转 int op; void read(int &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; }//读入优化 bool check() { //printf("\n---------------Check %d---------------\n",++op); for(int i=1;i<=9;i++) { int t=clocks[i]; //printf("i=%d,t=%d\n",i,t); for(int j=1;j<=9;j++) { t=(t+ans[j]*f[j][i])%4;//计算最后时针的位置 //printf("<j=%d,t=%d>",j,t); }//内层枚举转法 if(t) return 0;//如果不为0=>没有指向12=>返回false }//外层枚举钟 return 1;//之前没有返回=>所有钟都指向12=>返回true } void print()//输出 { bool flag=1;//防止多余空格 for(int i=1;i<=9;i++)//枚举每种转法 for(int j=1;j<=ans[i];j++)//转了几次输出几个 if(flag) printf("%d",i),flag=0; else printf(" %d",i); } void dfs(int x)//枚举转法 { if(check()) { print(); exit(0);//exit(0)用于在函数递归中直接结束程序(头文件:cstdlib) } for(int i=0;i<4;i++)//枚举转的次数 { ans[x]=i;//保存下来 if(x<=9) dfs(x+1);//只要转法符合条件就可以递归(注意是“<=”,因为如果第i次递归有了正确答案,要第i+1次递归才能输出) } } int main() { for(int i=1;i<=9;i++) read(clocks[i]); dfs(1); }
对于上面的“x<=9”,可以这样写: -
void dfs(int x) { for(int i=0;i<4;i++) { ans[x]=i; if(check()) { print(); exit(0); } if(x<9) dfs(x+1); } }
这就是dfs的标准格式之一了。 -
- By WZY
-