任意給定一個正整數N,求一個最小的正整數M(M>1),使得N*M的十進制表示形式裏只含有1和0.算法
如N=3,M=39,N*M=111。數組
【思路】spa
這麼難的思路打死我也想不到.@_@|||||..code
將題目轉換爲,求一個數X,使得X%N=0且X的十進制表示只含有1和0.blog
維護一個「餘數數組」,對於從0到N-1的每個餘數,都有相應的最小X;class
高位能夠利用低位的餘數歸隊,X=10^k+Y(10的k次方,^表示次方)X%N=(10^k%N+Y%N).擴展
直到找到餘數爲0對應的最小值。date
【other code】——via xiaodongrush總結
int find_m(int n) { if(n==1) return 1; int factor=10; int *A=new int[n];//A[i]保存餘數爲i時對應的最小數 int *B=new int[n];//B[i]保存餘數爲i的當前數 bool not_find=true; memset(A, -1, n*sizeof(int)); A[1]=1; while(not_find){ memset(B, -1, n*sizeof(int)); int x=factor%n;//餘數 if(A[x]==-1){ B[x]=factor; if(x==0) break; } for(int i=1; i<n; i++){ if(A[i]==-1) continue; int new_x=(x+i)%n; if(A[new_x]==-1&&B[new_x]==-1){ B[new_x]=factor+A[i]; if(new_x==0){ not_find=false; break; } } } factor*=10; for(int i=0; i<n; i++){ if(A[i]==-1&&B[i]!=-1) A[i]=B[i]; } } int result=B[0]; delete [] A; delete [] B; return result; }
【評價】di
維護兩個數組,A保存餘數對應的最小值,B保存當前值,每當有新餘數時便擴展。按照書上的算法來的,十分嚴密,對於我來講已經很perfect了。
【書上的僞代碼】
int find_m1(int n) { int Noupdate=0; int i,j; vector<vector<int> > BigInt(n); for(int i=0; i<n; i++) BigInt[i].clear(); BigInt[1].push_back(0); for(i=1, j=10%n; ; i++, j=(j*10)%n){ bool flag=false;//判斷是否更新 if(BigInt[j].size()==0){ flag=true; BigInt[j].clear(); BigInt[j].push_back(i); } for(int k=1; k<n; k++){ if((BigInt[k].size()>0)&& (i>BigInt[k][BigInt[k].size()-1])&& (BigInt[(j+k)%n].size()==0)){ flag=true; BigInt[(j+k)%n]=BigInt[k]; BigInt[(j+k)%n].push_back(i); } } if(flag==false) Noupdate++; else Noupdate=0; if(Noupdate==n||BigInt[0].size()>0) break; } if(BigInt[0].size()==0) return -1; else{ int result=0; int factor=1; for(int k=0; k<BigInt[0].size(); k++){ for(int r=0; r<BigInt[0][k]; r++) factor*=10; result+=factor; factor=1; } return result; } }
【總結】
僞代碼中10^k表示的是異或運算。用一個vector<vector<int> >來保存餘數信息。
BigInt[i]是餘數i對應最小數的有1的位置,好比對於n=3,BigInt[0] (0,1,2)表明第0,1,2位都有1,即111.
最後要轉化成十進制表示。