题目及翻译
题面
假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
I. 第 i 位的数字能被 i 整除
II. i 能被第 i 位上的数字整除
现在输入一个整数 N,请问可以构造多少个优美的排列?
输入
输入样例由多组测试数据组成。每组测试数据第一行输入一个正整数 N ( 1 <= N <= 15 )
输出
输出可以构造的优美的排列的数量
输入样例
2
输出样例
2
提示
参照输入样例:
第 1 个优美的排列是 [1, 2]:
第 1 个位置(i=1)上的数字是1,1能被 i(i=1)整除
第 2 个位置(i=2)上的数字是2,2能被 i(i=2)整除
第 2 个优美的排列是 [2, 1]:
第 1 个位置(i=1)上的数字是2,2能被 i(i=1)整除
第 2 个位置(i=2)上的数字是1,i(i=2)能被 1 整除
题目思路
给学弟学妹写篇题解,小不点们加油!!
有不懂的地方欢迎留言或者微信找我询问~
这题递归的确很方便,比之之前的题目好歹要带回溯了,其实是我没想到不回溯的递归方式
乍一看很麻烦,但是只要透析题目的本质,这题就很简单
对于每一个位置 i,从1到n里选择一个被i整除的数或者i的倍数,标记其被使用过,然后递归下一个位置到结束即可
注意事项
为了与答案匹配,应该选择从1开始的位置递归到n,到达n + 1时才退出
AC代码
C/C++(代码几乎没有变更)
用时72MS 内存1120K 长度347B
#include<stdio.h>
int n;
int vis[20];
int dfs(int cur){//cur用来表示当前所处位置,从1开始到n
if(cur == n + 1)return 1;//到n+1时说明所有位置都被安排好了,就退出
int sum = 0;//统计结果,如果结果为0意味着目前情况没有答案
for(int i=1;i<=n;++i){//从1到n遍历
if(vis[i])continue;//如果这个数被用过,就跳过
if((i % cur) && (cur % i))continue;//如果这个数和i互相都不是对方的倍数,就跳过
vis[i] = 1;//使用这个数
sum += dfs(cur + 1);//统计使用了i这个数的所有情况
vis[i] = 0;//回溯
}
return sum;
}
int main(){
while(~scanf("%d",&n)){//循环输入到文件尾
printf("%d\n",dfs(1));//弹出
}
return 0;
}
本文作者 CSDN@扶她小藜
个人主页链接 https://blog.csdn.net/weixin_44579869