暴力求解法 之 简单枚举
生活随笔
收集整理的這篇文章主要介紹了
暴力求解法 之 简单枚举
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1、除法
? ? 輸入正整數n,按從小到大的順序輸出所有形如abcde / fghij = n的表達式,其中a~j恰好為0~9的一個排列,2<=n<=79.
? ? 樣例輸入:62
? ? 樣例輸出: ?79546 / 01283 =62
? ? ? ? ? ? ? ? ? ? ? 94736 / 01528 =62
分析: 枚舉0~9的所有排列?沒這個必要。只需要枚舉fghij就可以算出abcde,然后判斷是否所有數字都不相同即可。不僅程序簡單,而且枚舉量也從10!=3628800降低至不到1萬。
#include<stdio.h>
#include<string.h>
int main()
{int i,j,n,s1,s2,flag[10];while(~scanf("%d",&n)){for(i=1234;i<50000;i++){memset(flag,0,sizeof(flag));/*flag保存每一位數字*/s1=i;s2=i*n;while(s1||s2){if(!flag[s1%10]){flag[s1%10]=1;s1/=10;}elsebreak;if(!flag[s2%10]){flag[s2%10]=1;s2/=10;}elsebreak;}for(j=0;j<10;j++)if(!flag[j])break; /*判斷是否是10個各不相同的數字*/if(j==10&&i*n<=98765) /*如果數字各不相同*/{if(i<10000) /*除數是一個四位數,有前導0*/printf("%d / 0%d = %d\n",i*n,i,n);elseprintf("%d / %d = %d\n",i*n,i,n);}}}return 0;
}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2、最大乘積 輸入n個元素組成的序列s,你需要找出一個乘積最大的的連續子序列。如果這個最大的的乘積不是正數,輸出-1.1<=n<=18,-10<=Si<=10; 樣例輸入: 3 2 4 -3 5 2 5 -1 2 -1 樣例輸出: 8? 20 分析:連續子序列有兩個要素:起點和終點,因此只需枚舉起點和終點即可。由于每個元素的絕對值不超過10,一共又不超過18個元素,最大可能的乘積不會超過10^18,可以用long long 存下。 #include<stdio.h> #include<string.h> const int inf=999999; int main() {long long a[20],s[20];long long i,j,n,max;while(~scanf("%lld",&n)){memset(s,0,sizeof(s));s[0]=1;max=-inf;for(i=1;i<=n;i++){scanf("%lld",&a[i]);s[i]=s[i-1]*a[i];/*s[i]表示從第一個數到第i個數的乘積*/}for(i=1;i<=n;i++) /*子序列長度*/{for(j=i;j<=n;j++){if(s[j]/s[j-i]>max)max=s[j]/s[j-i];}}if(max<0)max=-1;printf("%lld\n",max);}return 0; }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3、分數拆分 輸入正整數k,找到所有的正整數x>=y,使得1/k=1/x + 1/y; 樣例輸入: 2 12 樣例輸出: 2 1/2 = 1/6 + 1/3 1/2 = 1/4 + 1/4 8 1/12 = 1/156 + 1/13 1/12 = 1/84 + 1/14 1/12 = 1/60 + 1/15
1/12 = 1/48 + 1/16
1/12 = 1/36 + 1/18
1/12 = 1/30 + 1/20
1/12 = 1/28 + 1/21
1/12 = 1/24 + 1/24
從1/12=1/156+1/13可以看出,x可以比y大很多。由于x>=y,有1/x<=1/y,因此1/k-1/y<=1/y,即y<=2*k.這樣,只需要在2*k范圍之內枚舉y,然后根據y嘗試計算出x即可。 #include<stdio.h> #include<string.h> struct integer {int X,Y; }a[10000]; int main() {int i,j,y,k,count;while(~scanf("%d",&k)){memset(a,0,sizeof(a));i=count=0;for(y=k+1;y<=k*2;y++){if(y*k%(y-k)==0){count++;a[i].X=y*k/(y-k);a[i++].Y=y;}}printf("%d\n",count);for(j=0;j<i;j++)printf("1/%d = 1/%d + 1/%d\n",k,a[j].X,a[j].Y);}return 0; }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4、雙基回文數 ?如果一個正整數n至少在兩種不同的進制下b1和b2下都是回文數(2<=b1,b2<=10),則稱n是雙基回文數(注意,回文數不能包含前導零)。輸入正整數S<10^6,輸出比S大的最小的雙基回文數。 樣例輸入: ?1600000 樣例輸出: ?1632995 分析:最自然的想法就是:從n+1開始依次判斷每個數是否為雙基回文數,而在判斷時枚舉所有可能的基數(2~10),一切都是那么的“暴力”。令人有些意外的是:這樣做對于S<10^6這樣的“小規模數據”來說是足夠快的——雙基回文數太多太密了。 #include<stdio.h> int a[30]; int huiwen(int s[],int n) /*判斷是否回文*/ {int i;for(i=0;i<=n/2;i++){if(a[i]!=a[n-i]){return 0;break;}}return 1; } int converse(int n,int k) /*把十進制的n轉化為k進制*/ {int flag=0,i,j=0;while(n){a[j++]=n%k;n/=k;}if(huiwen(a,j-1))flag=1; if(flag) /*n在k進制下是回文數*/return 1;elsereturn 0; } int main() {int i,j,k,n,cnt;while(~scanf("%d",&n)){for(j=n+1;;j++){int p=0;for(i=2,cnt=0;i<=10;i++){if(converse(j,i))cnt++; /*記錄回文次數*/if(cnt>=2) /*是雙基回文數*/{p=1;break;}}if(p){printf("%d\n",j);break;}}}return 0; }
與50位技術專家面對面20年技術見證,附贈技術全景圖
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2、最大乘積 輸入n個元素組成的序列s,你需要找出一個乘積最大的的連續子序列。如果這個最大的的乘積不是正數,輸出-1.1<=n<=18,-10<=Si<=10; 樣例輸入: 3 2 4 -3 5 2 5 -1 2 -1 樣例輸出: 8? 20 分析:連續子序列有兩個要素:起點和終點,因此只需枚舉起點和終點即可。由于每個元素的絕對值不超過10,一共又不超過18個元素,最大可能的乘積不會超過10^18,可以用long long 存下。 #include<stdio.h> #include<string.h> const int inf=999999; int main() {long long a[20],s[20];long long i,j,n,max;while(~scanf("%lld",&n)){memset(s,0,sizeof(s));s[0]=1;max=-inf;for(i=1;i<=n;i++){scanf("%lld",&a[i]);s[i]=s[i-1]*a[i];/*s[i]表示從第一個數到第i個數的乘積*/}for(i=1;i<=n;i++) /*子序列長度*/{for(j=i;j<=n;j++){if(s[j]/s[j-i]>max)max=s[j]/s[j-i];}}if(max<0)max=-1;printf("%lld\n",max);}return 0; }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3、分數拆分 輸入正整數k,找到所有的正整數x>=y,使得1/k=1/x + 1/y; 樣例輸入: 2 12 樣例輸出: 2 1/2 = 1/6 + 1/3 1/2 = 1/4 + 1/4 8 1/12 = 1/156 + 1/13 1/12 = 1/84 + 1/14 1/12 = 1/60 + 1/15
1/12 = 1/48 + 1/16
1/12 = 1/36 + 1/18
1/12 = 1/30 + 1/20
1/12 = 1/28 + 1/21
1/12 = 1/24 + 1/24
從1/12=1/156+1/13可以看出,x可以比y大很多。由于x>=y,有1/x<=1/y,因此1/k-1/y<=1/y,即y<=2*k.這樣,只需要在2*k范圍之內枚舉y,然后根據y嘗試計算出x即可。 #include<stdio.h> #include<string.h> struct integer {int X,Y; }a[10000]; int main() {int i,j,y,k,count;while(~scanf("%d",&k)){memset(a,0,sizeof(a));i=count=0;for(y=k+1;y<=k*2;y++){if(y*k%(y-k)==0){count++;a[i].X=y*k/(y-k);a[i++].Y=y;}}printf("%d\n",count);for(j=0;j<i;j++)printf("1/%d = 1/%d + 1/%d\n",k,a[j].X,a[j].Y);}return 0; }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4、雙基回文數 ?如果一個正整數n至少在兩種不同的進制下b1和b2下都是回文數(2<=b1,b2<=10),則稱n是雙基回文數(注意,回文數不能包含前導零)。輸入正整數S<10^6,輸出比S大的最小的雙基回文數。 樣例輸入: ?1600000 樣例輸出: ?1632995 分析:最自然的想法就是:從n+1開始依次判斷每個數是否為雙基回文數,而在判斷時枚舉所有可能的基數(2~10),一切都是那么的“暴力”。令人有些意外的是:這樣做對于S<10^6這樣的“小規模數據”來說是足夠快的——雙基回文數太多太密了。 #include<stdio.h> int a[30]; int huiwen(int s[],int n) /*判斷是否回文*/ {int i;for(i=0;i<=n/2;i++){if(a[i]!=a[n-i]){return 0;break;}}return 1; } int converse(int n,int k) /*把十進制的n轉化為k進制*/ {int flag=0,i,j=0;while(n){a[j++]=n%k;n/=k;}if(huiwen(a,j-1))flag=1; if(flag) /*n在k進制下是回文數*/return 1;elsereturn 0; } int main() {int i,j,k,n,cnt;while(~scanf("%d",&n)){for(j=n+1;;j++){int p=0;for(i=2,cnt=0;i<=10;i++){if(converse(j,i))cnt++; /*記錄回文次數*/if(cnt>=2) /*是雙基回文數*/{p=1;break;}}if(p){printf("%d\n",j);break;}}}return 0; }
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的暴力求解法 之 简单枚举的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一条看似不合理SQL和10个合理的解释
- 下一篇: 原创 | 我说我了解集合类,面试官竟然问