"Forever number" is a positive integer A with K digits, satisfying the following constrains:git
Now you are supposed to find these forever numbers.算法
Each input file contains one test case. For each test case, the first line contains a positive integer N (≤5). Then N lines follow, each gives a pair of K (3<K<10) and m (1<m<90), of which the meanings are given in the problem description.編程
For each pair of K and m, first print in a line Case X
, where X
is the case index (starts from 1). Then print n and A in the following line. The numbers must be separated by a space. If the solution is not unique, output in the ascending order of n. If still not unique, output in the ascending order of A. If there is no solution, output No Solution
.函數
2 6 45 7 80
Case 1 10 189999 10 279999 10 369999 10 459999 10 549999 10 639999 10 729999 10 819999 10 909999 Case 2 No Solution
現給定一個數字A的總位數K和全部位數之和m,要求你尋找這樣的一個數字n,n爲A+1的全部數位之和,m和n的最大公約數G,並G大於2且爲素數,輸出全部的n和A,不然輸出No Solution。測試
第一反應此題和全排列的問題即爲類似,就是添加了約束條件。那麼其本質就是使用暴力搜索,很容易就想到使用DFS進行求解。可是直接進行DFS最後一個點會超時,因此得弄清楚剪枝條件,咱們假設如今搜索到第depth
位,當前的總數位之和爲m
,數字爲num
,那麼後面尚未搜索的數位有K-depth
位。那麼剪枝的條件就是,若是當前的總數位之和m+後面未搜索的最大總數位之和9*(K-depth)
小於K
,那麼就說明不管怎樣取值,都不可能存在一個數的總數位m符合題目要求。這樣DFS的超時問題就解決了,如今只須要求解任意2數的最大公約數和任意一個數字的位數之和,就能夠編寫DFS函數了。優化
// 適用於a,b較小的狀況 int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); } // 適用於a,b較大的狀況(編程之美2.7章節) int gcd(int a,int b){ if(a<b) return gcd(b,a); if(b==0){ return a; } else { if(a%2==0){ if(b%2==0){ return 2*gcd(a/2,b/2); } else { return gcd(a/2,b); } } else{ if(b%2==0){ return gcd(a,b/2); } else { return gcd(b,a-b); } } } }
int getDigitSum(int num){ int m = 0; while (num!=0){ m += num%10; num /= 10; } return m; }
/* * depth:當前深度,表明選擇第幾位,初始爲0 * m:當前已經選擇的位數之和,好比選擇了3次,分別是1,4,5,那麼m=1+4+5=10 * num:當前已經選擇的位數所表明的數字,好比選擇了3次,分別是1,4,5,那麼num=145 * */ void DFS(int depth,int m,int num){ if(depth==K&&m==M){ int n = getDigitSum(num+1);// 獲得n int G = gcd(m,n); if(G>2&&isPrime(G)){ // 保存結果集 result.emplace_back(num,n); } return; } // 剩餘最大值之和都小於所須要的,不可能有解 if(m+9*(K-depth)<M||depth>K) return; for(int i=0;i<=9;++i){ DFS(depth+1,m+i,num*10+i); } }
到這裏DFS並無結束,由於還有能夠優化的點(上面的代碼已經能夠經過測試了),由於第一位必定是1,不多是0,最後兩位必定是99。第一位是1比較好想的到,最後兩位爲何是99呢?spa
首先對於任意2個相鄰數字的最大公約數爲1,好比6和7,要想m和n的最大公約數大於2,首先就是要求m和n不能是相鄰的兩個數字,那麼要求m和n不相鄰,就得保證A的最後一個數字得是9,否則A+1沒有進位,n=m+1。可是若是隻有最後一位爲9依然仍是不行,由於若是隻有一個9,那麼A+1的全部數位之和n=m-9+1(最後的9進位了),那麼n與m的最大公約數等價於8和m的最大公約數(展轉相除法,不懂得看編程之美2.7章節),可是8的約數只有1,2,4,8,均不是大於2的素數,因此最後一位還得是9,由於不是9的化,n依然等於m-8。最後2位爲9之後,n=m-9-9+1(2個9都進位了),這樣n和m的公約數就轉化爲m和17的公約數了,若是m剛好整除17,就獲得了一個大於2的素數,因此最後2位必定是9。3d
/* * depth:當前深度,表明選擇第幾位,初始爲0 * m:當前已經選擇的位數之和,好比選擇了3次,分別是1,4,5,那麼m=1+4+5=10 * num:當前已經選擇的位數所表明的數字,好比選擇了3次,分別是1,4,5,那麼num=145 * */ void DFS(int depth,int m,int num){ if(depth==K&&m==M){ int n = getDigitSum(num+1);// 獲得n int G = gcd(m,n); if(G>2&&isPrime(G)){ result.emplace_back(num,n); } return; } // 剩餘最大值之和都小於所須要的,不可能有解 if(m+9*(K-depth)<M||depth>K) return; // 第一位必定爲1,最後2位必定爲9 int i = depth==0 ? 1: depth==K-1||depth==K-2? 9 : 0; for(;i<=9;++i){ DFS(depth+1,m+i,num*10+i); } }
最後使用result保存全部的結果集,而後排序輸出便可。code
#include<cstdio> #include<vector> #include<cmath> #include <algorithm> using namespace std; struct Node{ int A; int n; Node(int _A,int _n){ A = _A; n = _n; } }; int K,M;// 總位數,總位數之和 vector<Node > result; bool cmp(const Node &a,const Node &b){ return a.n!=b.n?a.n<b.n:a.A<b.A; } int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); } bool isPrime(int n){ if(n<=1) return false; int sqrtn = (int)sqrt(n*1.0); for(int i=2;i<=sqrtn;++i){ if(n%i==0) return false; } return true; } int getDigitSum(int num){ int m = 0; while (num!=0){ m += num%10; num /= 10; } return m; } /* * depth:當前深度,表明選擇第幾位,初始爲0 * m:當前已經選擇的位數之和,好比選擇了3次,分別是1,4,5,那麼m=1+4+5=10 * num:當前已經選擇的位數所表明的數字,好比選擇了3次,分別是1,4,5,那麼num=145 * */ void DFS(int depth,int m,int num){ if(depth==K&&m==M){ int n = getDigitSum(num+1);// 獲得n int G = gcd(m,n); if(G>2&&isPrime(G)){ result.emplace_back(num,n); } return; } // 剩餘最大值之和都小於所須要的,不可能有解 if(m+9*(K-depth)<M||depth>K) return; // 第一位必定爲1,最後2位必定爲9 int i = depth==0 ? 1: depth==K-1||depth==K-2? 9 : 0; for(;i<=9;++i){ DFS(depth+1,m+i,num*10+i); } } int main(){ int N; scanf("%d",&N); for(int i=0;i<N;++i){ scanf("%d %d",&K,&M); printf("Case %d\n",i+1); result.clear(); DFS(0,0,0); sort(result.begin(), result.end(),cmp); for (auto &item : result) { printf("%d %d\n",item.n,item.A); } if (result.empty()) { printf("No Solution\n"); } } return 0; }