题目意思: 给定n和m 现在要求找到一个m位数的树使得,对于m的前i位数都是i的倍数,n <= i <= m, 而且这个数的第一位数不能为0,如果找到就输出这个数,否则输出-1
解题思路: 1 目前只懂得用深搜回溯做,只是这一题的数据没有想象中的那么大,所以加上一些剪枝即可水过(数据强的话肯定TLE)
2 我们知道这个解空间树有m层,每一层的可能取值有10种(第一个除外),那么最大的m = 29 ,那么时间复杂都就是 10^29次方,这么大的时间你敢用吗。由于这一 题的数据比较水,那么可以过。但是由于最大的数值超过了int,我们必须用数组模拟。
3 思路: 从第一层开始搜索,注意第一层不能为0,我们用k(这里第一层k = 1)表示当前的层数。对于k < n时候我们不用考虑能否被k整除直接往下搜素,当k >= n 时候我们就要考虑当前的这个大数能否被k整除,如果可以就往下继续搜索,最后如果当k > m时候说明已经找到了,并且我们已经从0开始搜索,那么得到的答案就是最小值,这时候可以直接输出
4 注意事项:由于刚开始,我认为前i-1个位数是不用要求被当前的位数整除,并且认为第一个数就是1,然后就开了一段WA历程,后来找到了数据才发现尼玛坑爹啊哥哥我错了。第一位值不一定为1,所以我们必须从第一层开始向下搜索至m层,所以看到这个m这么大,你敢这么做吗
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <vector> #include <cstdio> #include <stack> #include <queue> #include <cmath> using namespace std; int t , n , m , flag; int ans[50]; //判断当前数值能否被整除 int judge_divisible(int *tmp , int k){ int d = 0;//d是于数 for(int i = 1 ; i <= k ; i++){//从小到大来模拟除法运算 d = d*10+tmp[i]; d %= k; } return d;//直接返回说明有没有于数存在 } //深搜(就去枚举每一个位数的情况) void dfs(int Tans[] , int k){ if(k > m) { memcpy(ans , Tans , sizeof(ans)); flag = 1 ; return; }//如果当前的位数超过了m说明找到了这个标记flag为1 for(int i = 0 ; i <= 9 ; i++){//枚举10个可能的值 Tans[k] = i;//令这个位数的数值为i,就去判断能否符合 if(Tans[1] != 0){ if(k < n || k >= n && !judge_divisible(Tans , k)) dfs(Tans , k+1);//继续深搜 if(flag) return;//找到了就直接返回不再去搜索就是剪枝 } } } //主函数 int main(){ //freopen("input.txt" , "r" , stdin); int i , j; scanf("%d" , &t); for(i = 1 ; i <= t ; i++){ scanf("%d%d" , &n , &m); memset(ans , 0 , sizeof(ans)); flag = 0 ; dfs(ans , 1); printf("Case %d: " , i); if(flag){//如果当前有最小值输出这个值 for(j = 1 ; j <= m ; j++) printf("%d" , ans[j]); }//没有的话输出-1 else printf("-1"); printf("\n"); } return 0; }