枚举----暴力枚举

第一题

题目描述

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187
都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。

思路

暴力枚举,四重循环, abcd的值分别从0到9开始 ,然后判断abcd不能相等,然后在不相等的条件下进行乘法运算。乘法运算分为两种情况
a * bcd 和 ab * cd
abcd分别从0-9开始遍历,第一种情况不会出现重复,但第二种情况可能会出现重复,一开始觉得重复会发生在ab大于50 的情况,结果发现 35 和41 也会重复,所以就直接全部遍历再除2解决。

判断结果是否和原来的数字组成相同用的最直观的思路,先两个数字都排序,然后依次遍历是否相等,反正就4位。。相同则++计数。

一开始想两种循环嵌套一起,但是分不清ab cd交换律相同的情况,就将两种情况分别讨论。

结果

12

代码

#include 
#include 

using namespace std;

int main() {
    int a,b,c,d,answer,count=0 , count1 = 0 ;
    int org[4];
    int ans[4];
    for(a = 0; a<10 ; a++){
        for(b = 0 ; b < 10; b++){
            for(c = 0 ; c < 10 ; c++){
                for (d = 0 ; d < 10 ; d++){
                    if(a!= b && a!=c && a!=d && b!=c && b!=d && c!=d){
                       org[0] = a; org[1] = b ; org[2] = c; org[3] = d;
                       sort(org,org+4);
                        answer = a *(b*100+c*10+d);
                        if(answer >1000 && answer < 9999){
                            ans[0] = answer%10; answer = answer/10;
                            ans[1] = answer%10; answer = answer/10;
                            ans[2] = answer%10; answer = answer/10;
                            ans[3] = answer%10;
                            sort(ans,ans+4);

                            for (int i = 0; i < 4; ++i) {
                                if (ans[i] != org[i]){
                                    break;
                                }
                                if(i == 3){
                                    count++;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    for(a = 0; a<10 ; a++){
        for(b = 0 ; b < 10; b++){
            for(c = 0 ; c < 10 ; c++){
                for (d = 0 ; d < 10 ; d++){
                    if(a!= b && a!=c && a!=d && b!=c && b!=d && c!=d){
                        org[0] = a; org[1] = b ; org[2] = c; org[3] = d;
                        sort(org,org+4);

                        answer = (a*10+b)*(c*10+d);
                            if(answer >1000 && answer < 9999){
                                ans[0] = answer%10; answer = answer/10;
                                ans[1] = answer%10; answer = answer/10;
                                ans[2] = answer%10; answer = answer/10;
                                ans[3] = answer%10;
                                sort(ans,ans+4);
                                for (int i = 0; i < 4; ++i) {
                                    if (ans[i] != org[i]){
                                        break;
                                    }
                                    if(i == 3) {
                                        count1++;
                                    }

                                }
                            }
                    }
                }
            }
        }
    }

    cout<< count+(count1/2);
}

第二题

题目描述

小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。
其标价都是4位数字(即千元不等)。
小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了。
这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 68 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,比如:1958 倒着挂就是:8561,差了几千元啊!!
当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。
有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了!
庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。
请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少?

思路

暴力枚举,就先枚举到赚了800多的情况,然后在这种情况下,暴力枚举到赔了200多的情况,然后两者相减,判断是不是558。

几点要考虑的

  1. 凑数
  2. 翻转

对于凑数:这两种情况发生在正看反过来都有意义的数,所以3,4,7可以不参与凑数过程。其次,原价为4位数,则凑数时千位不能为0。那就构造可以凑的数的数组,propNum[7] = {0,1,2,5,6,8,9}。四重循环,得原始数据。

对于翻转,只有6和9的情况会发生数字的变化,则依次判断是否为6或者9。每一位在一个if中判断,否则会出现,第一个if中判断,然后把6改成了9,然后再if就给改回去了的情况。。

结果

9088
赚的吊盘:1061

代码

#include 

using namespace std;

int main() {
    int propNum[7] = {0,1,2,5,6,8,9};
    int org_E= 0 , exc_E = 0 , org_T = 0 , exc_T = 0;
    int a,b,c,d;
    for (int i = 1; i < 7; ++i) {
        a = propNum[i];
        for (int j = 0; j < 7; ++j) {
            b = propNum[j];
            for (int k = 0; k < 7; ++k) {
                c = propNum[k];
                for (int l = 0; l < 7; ++l) {
                    d = propNum[l];

                    org_E = a*1000+b*100+c*10+d;
                    if (a==6 || a==9){
                        if (a == 6) a=9;
                        else a = 6 ;
                    }
                    if (b==6 || b==9){
                        if (b == 6) b=9;
                        else b = 6 ;
                    }
                    if (c==6 || c==9){
                        if (c == 6) c=9;
                        else c = 6 ;
                    }
                    if (d==6 || d==9){
                        if (d == 6) d=9;
                        else d = 6 ;
                    }
                    exc_E = d*1000+c*100+b*10+a;
                    if(exc_E - org_E > 800 && exc_E-org_E <900){
                      //  cout << org_E<<"  "<
                        for (int m = 1; m < 7; ++m) {
                            a = propNum[m];
                            for (int n = 0; n < 7; ++n) {
                                b = propNum[n];
                                for (int i1 = 0; i1 < 7; ++i1) {
                                    c = propNum[i1];
                                    for (int j1 = 0; j1 < 7; ++j1) {
                                        d = propNum[j1];
                                        org_T = a*1000+b*100+c*10+d;
                                        if (a==6 || a==9){
                                            if (a == 6) a=9;
                                            else a = 6 ;
                                        }
                                        if (b==6 || b==9){
                                            if (b == 6) b=9;
                                            else b = 6 ;
                                        }
                                        if (c==6 || c==9){
                                            if (c == 6) c=9;
                                            else c = 6 ;
                                        }
                                        if (d==6 || d==9){
                                            if (d == 6) d=9;
                                            else d = 6 ;
                                        }
                                        exc_T = d*1000+c*100+b*10+a;
                                        if(org_T-exc_T > 200 && org_T-exc_T<300){
                                            if((exc_E - org_E)-(org_T-exc_T)==558){
                                                cout << org_T;
                                                return 0;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

第三题

题目描述

X星系的机器人可以自动复制自己。它们用1年的时间可以复制出2个自己,然后就失去复制能力。
每年X星系都会选出1个新出生的机器人发往太空。也就是说,如果X星系原有机器人5个,
1年后总数是:5 + 9 = 14
2年后总数是:5 + 9 + 17 = 31
如果已经探测经过n年后的机器人总数s,你能算出最初有多少机器人吗?
输入:
输入一行两个数字n和s,用空格分开,含义如上。n不大于100,s位数不超过50位。
输出:
要求输出一行,一个整数,表示最初有机器人多少个。

样例

输入: 2 31
输出:5

思路

从有一个开始试,试到n年,看此时的结果是不是输入的总人数。是就输出并退出,不是的话就继续。
并没有oj可以测试,所以就猜着做,感觉可能会超时。。
s有50位,所以得设成longlong类型。
核心过程就是题目描述的,按照变量表示就可以了。今年能产生的机器人数量=去年的*2-1。然后爸今年产生的家在总count里。判断count和输入的一不一样。

代码

#include 

using namespace std;

int main() {
    int n;
    long long total,count = 0,thisYear=0,lastYear=0 ;
    cin >> n >>total;
    for (int i = 1; i < total; ++i) {
        count = i; thisYear = i;
        for (int j = 0; j < n; ++j) {
            lastYear = thisYear;
            thisYear = lastYear*2-1;
            count+= thisYear;
        }
        if (count == total) {
            cout << i;
            return 0;
        } else continue;
    }
}


第四题

题目描述

小明正看着 203879 这个数字发呆。 原来,203879 * 203879 = 41566646641这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。具有这样特点的6位数还有一个,请你找出它!
再归纳一下筛选要求:

  1. 6位正整数
  2. 每个数位上的数字不同
  3. 其平方数的每个数位不含原数字的任何组成数位

输出:
输出这另一个数字

思路

依次枚举,取得互不相同的6位数,平方,此时只有unsigned long long能存下,long long 也不行。然后%10 /10 依次判断是否出现在原始数组。通过一个bool的数组来完成。
每次循环把数组清空。要不然会带着上一次的结果。。
另写一个判断函数,不在主循环里判断是否有数字和原来相等,要不然break并不能跳出本次循环,枚举下一种情况,只能跳出while。

结果

639172

代码

#include 
#include 

using namespace std;
bool arr[10]={false};

bool judge(int a){
    int temp;
    unsigned long long res;
    res = pow(a,2);
    while (res!=0){
        temp = res%10;
        res = res/10;
        if(arr[temp]) return false;
    }
    return true;
}

int main() {
    int org,temp;
    long long res;
    int a,b,c,d,e,f;
    for(a = 1 ; a < 10 ; a++){
        for(b = 0; b < 10 ; b++){
            for(c = 0 ; c < 10 ; c++){
                for(d = 0 ; d < 10 ; d++){
                    for(e = 0 ; e < 10; e++){
                        for(f = 1 ; f < 10 ; f++){
                            if(a!=b && a!=c && a!=d && a!=e && a!=f &&
                            b!=c && b!=d && b!=e &&b!=f&&
                            c!=d && c!=e && c!=f &&
                            d!=e && d!=f &&
                            e!=f){
                                for (int i = 0; i < 10; ++i) {
                                    arr[i] = false;
                                }
                              arr[a] = true;arr[b] = true;arr[c] = true;
                              arr[d] = true;arr[e] = true;arr[f] = true;
                              org = a*100000+b*10000+c*1000+d*100+e*10+f;
                              if(judge(org)){
                                  cout << org<<endl;
                                  break;
                              }
                            }
                        }
                    }
                }
            }
        }
    }
}


第五题

题目描述:

福尔摩斯从X星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为8的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。
请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。
输入:
输入第一行:一个字符串s,全部由小写字母组成,长度小于1024*1024
紧接着一行是一个整数n,表示以下有n行密码,1<=n<=1000
紧接着是n行字符串,都是小写字母组成,长度都为8
输出:
一个整数, 表示每行密码的所有排列在s中匹配次数的总和。

样例

输入:
aaaabbbbaabbcccc
2
aaaabbbb
abcabccc
输出:
4

思路

首先看懂4是怎么来的。
子串1 aaaabbbb 可以匹配母串1-8位;子串变换为aaabbbba,匹配母串2-9位;子串变换为aabbbbaa,匹配母串3-10位置。
子串2 abcabccc,可以变换为aabbcccc,匹配母串最后8位。
所以一共4种情况。

转换思路:

子串无论怎么变化,字符个数不会发生变化。也就是子串1就是4个a,4个b。子串2就是2个a,2个b,4个c。子串匹配母串的某一位置,就是看在母串[x,x+8]的位置上是不是和子串有相同的字符数量。如果字符数量相同,那么子串一定可以通过某种排列方式变换为母串。
就像子串1是4个a,4个b,母串1-8位是4个a,4个b,那么子串一定可以变换从而匹配,count+1;母串2-9位也是4个a,4个b,那么子串同样可以变化进行匹配,以此类推 母串3-10位也可以,其余的不再匹配。子串2共有2个a,2个b,4个c,在母串最后8位是2个a,2个b,4个c,则子串2一定可以变换从而匹配。

那么,在这种思路下,处理每个子串行程一个int ziChar[26]的数组存储子串的各个字母的个数。枚举每一个母串的8位,形成一个int muChar[26]的数组存储母串截取的子串的字符个数,进行匹配比较,完全相同即可。

ps 我一开始的bug,遍历母串写的k < muString.length()-8,没有写等号,导致母串最后8位并没有截取到,导致第二种情况没有输出,debug时断点设的位置也不够好,一直以为cin没进去。。

代码

#include 
#include 

using namespace std;

bool judge(int ziChar[26], int muChar[26]){
    for (int i = 0; i < 26; ++i) {
        if (ziChar[i] != muChar[i]) return false;
    }
    return true;
}

int main() {
    string muString;
    string ziString;
    int n;
    cin >>muString;
    cin >>n;

    int count = 0 ;

    for (int i = 0; i < n; i++) {
        cin >> ziString;
        int ziChar[26] ={0};
        //处理子串
        for (int j = 0; j < 8; ++j) {
            ziChar[ziString[j]-97]++;
        }
        //截取母串
        for (int k = 0; k <= muString.length()-8; ++k) {
            string s;
            s = muString.substr(k,8);
            //获取截取的母串的字母
            int muChar[26]={0};
            for (int p = 0; p < 8; ++p) {
                muChar[s[p]-97]++;
            }
            //进行匹配
            if (judge(ziChar,muChar)) {
              // cout << "1"<
                count++;
            }
        }

    }
    cout << count;
}


第六题

题目描述

四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
输入:
程序输入为一个正整数N (N<5000000)
输出:
要求输出4个非负整数,按从小到大排序,中间用空格分开

思路

从小到大枚举就肯定是按序的了。只管思路就是4重循环,但一定超市。最后一层d可以通过开平方求出来,所以可以省掉最后一层。算了一下5000000开平方事2236多,所以每层循环的最大值就设置为2237。非常直观但不知道oj上会不会超时。。

代码

#include 
#include 

using namespace std;

int main() {
    int n,temp;
    int a,b,c;
    double d;

    cin >> n ;

    for(a = 0 ; a < 2237; a++){
        for(b = a ; b < 2237; b++){
            for(c = b ; c < 2237; c++){
                d = sqrt(n-a*a-b*b-c*c);
                if(d == int(d)){
                    cout << a<<" "<<b<<" "<<c<<" "<<d;
                    return 0;
                }
            }
        }
    }
}

第七题

题目描述

A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。 要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。请填写出所有符合要求的排列中,字典序最小的那个。
例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

思路

构造 – 判断 --(存储)-- 输出

思路1:

字典序最小就是 2 3 4 A的顺序。因为A是65,2是32。所以用5代替A。由于不熟悉string的库,所以方法比较蠢。。8重循环,枚举一个结果,再判断是不是符合4对牌的规则,就是2 3 4 5 各有两个。然后再判断数字的间隔和不合理。这样第一个输出就是字典序最小的。

思路2:

8重循环实在是蠢。。搜了一下。可以利用string库的全排列函数,然后用find函数判断两个字母的位置是不是符合要求,是就存到set里(自带排序),然后直接输出头。

结果

2342A3A4

代码

思路1的代码:
#include 
#include 
#include 

using namespace std;
int s[8]={0};

bool count(int s[8]){
    int arr[6] = {0};
    for (int i = 0; i < 8; ++i) {
        arr[s[i]]++;
    }
    if(arr[2] == arr[3] && arr[3]== arr[4]&& arr[4] == arr[5]&&arr[5]==2) return true;
    else return false;
}

bool judge(int a, int b){//a代表牌 b代表间隔
    int i = 0 ;
    while(s[i] != a){i++;}
    if(s[i] == s[i+b+1]){ return true;}
    else return false;
}

int main() {
    int a,b,c,d,e,f,g,h;
    for(a = 2; a <=5 ; a++){
        s[0] = a;
        for(b = 2; b<=5; b++){
            s[1] = b;
            for(c = 2; c <=5 ; c++){
                s[2] = c;
                for(d = 2; d<=5; d++){
                    s[3] = d;
                    for(e = 2 ; e <=5; e++){
                        s[4] = e;
                        for(f = 2; f <=5 ; f++){
                            s[5] = f;
                            for(g = 2; g<=5 ; g++){
                                s[6] = g;
                                for(h = 2 ; h <=5 ; h++){
                                    s[7] = h;
                                    if(count(s)){//数量合格
                                      //  cout<

                                        if(judge(5,1)&&judge(2,2)&&judge(3,3)&&judge(4,4)){
                                            cout<<a<<b<<c<<d<<e<<f<<g<<h<<endl;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

思路2的代码:
#include 
#include 
#include 

using namespace std;

int main() {
    string s = "223344AA";
    set<string> sSet;
    do{
        unsigned long beginA = s.find('A',0);
        unsigned long endA = s.find('A',beginA+1);
        unsigned long begin2 = s.find('2',0);
        unsigned long end2 = s.find('2',begin2+1);
        unsigned long begin3 = s.find('3',0);
        unsigned long end3 = s.find('3',begin3+1);
        unsigned long begin4 = s.find('4',0);
        unsigned long end4 = s.find('4',begin4+1);
        if(endA-beginA == 2 && end2-begin2 == 3&& end3-begin3 ==4 &&end4-begin4 == 5){
            sSet.insert(s);
        }
    }while(next_permutation(s.begin(),s.end()));
    set<string>::iterator it=sSet.begin();
    cout << *it <<endl;
}

find(‘’, )第一个位置是字符,第二个位置是起始位置,一定要在begin后+1,要不然就是begin的位置,不会变化。。

第八题

题目描述

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入:
两个正整数,表示每种包装中糖的颗数(都不多于1000)
输出:
一个正整数,表示最大不能买到的糖数

样例

输入 4 7
输出 17

思路

思路是并没有什么思路。。虽然觉得枚举一定可行,但是连续出现多少个就能认为后面的都连续了呢?感觉需要数学证明。可以想到的就是 输入的两个数一定互质。然后好像输出的数据也是质数?然后搜了一下就
a*b-a-b 就可以了。。没看到证明。

代码

#include 

using namespace std;

int main() {
    int a,b;
    cin >> a>>b;
    cout << a*b-a-b<<endl;
}

第九题

题目描述

A 村的元宵节灯会上有一迷题: 请猜谜 * 请猜谜 = 请边赏灯边猜 小明想,一定是每个汉字代表一个数字,不同的汉字代表不同的数字。 请你用计算机按小明的思路算一下,然后输出“请猜谜”三个字所代表的整数即可。
输入:
不需要输入
输出:
输出“请猜谜”三个字所代表的整数即可。

思路

请猜谜 分别设为ABC,请边赏灯边猜为ADEFDB,其中ABCDEF均不等。三重循环枚举ABC,乘方得结果,判断是不是六位数,再判断数字是不是合法。

代码

#include 

using namespace std;
int a,b,c,d1,d2,e,f;
bool judge(int ans){
    int a1,b1;
    b1 = ans%10;
    if(b1 != b) return false;
    ans = ans/10;
    d2 = ans%10;ans = ans/10;
    f = ans%10; ans = ans/10;
    e = ans%10; ans = ans/10;
    d1 = ans%10; ans = ans/10;
    a1 = ans%10;
    if(d1 !=d2) return false;
    if(a1!=a) return false;
    if(e!=f && e!= a && e!=b && e!=c &&e!=d1 &&f!=a && f!=b && f!=c && f!=d1) return true;

}

int main() {
    int ans,org;
    for(a = 1; a <= 9 ; a++){
        for(b = 0 ; b<= 9 ; b++){
            for(c = 2; c <=9 ; c++){
                if(a !=b && a!=c && b!=c){
                    org = a*100+b*10+c;
                    ans = org*org;
                    if(ans > 100000 && ans < 999999){
                        if(judge(ans)){
                            cout << org<<endl;
                        }
                    }
                }
            }
        }
    }
}

第十题

题目描述

①输入正整数n(如62),2<=n<=79;
②输出形如abcde/fghij=n的表达式,每行输出一个表达式,其中a ~ j 恰好为0~9的一种排列;

样例

输入:62
输出:
79546/01283=62
94736/01528=62

思路

第一反应 全排列,挨个除,显然复杂度过高。此题和四平方问题相同,都是可以用其余几个变量求出另一个变量。从而降低复杂度。
输入的num和a相乘可以得到b,表示的时候为b/a = num。由于是全排列,且前后都是五位,那么对于a来说最小为01234,最大为98765,那么就用a*num得b之后判断a和b是否唯一即可。
在判断a和b是否唯一的时候,重点是0的问题。在做%10和/10的时候,4位数隐藏的0并不会被记入。也就意味着a为四位数,b中含有0的时候,按照标准不可行,但是单纯的%10和/10会忽略掉a隐藏的0,让判断结果成了可行。所以应首先判断a和b是否为4位数,是的话首先将代表0的arr[0]加一。

输出使用printf格式化输出进行补0。

代码

#include 

using namespace std;

bool judge(int a, int b){
    int arr[10]={0};
    int temp;
    if(a >1000 && a <9999){arr[0]++;}
    if(b >1000 && b <9999){arr[0]++;}
    while(a!=0){
        temp = a%10;
        a = a/10;
        arr[temp]++;
    }
    while (b!=0){
        temp = b%10;
        b = b/10;
        arr[temp]++;
    }
    for (int i = 0; i < 10; ++i) {
        if(arr[i] != 1) return false;
    }
    return true;
}

int main() {
    int n;
    cin >> n ;
    int a , b;
    for(a = 1234; a <= 98765 ; a++){
        b = a * n;
        if(judge(a,b)){
            printf("%05d/%05d = %d\n",b,a,n);
        }
    }
}

你可能感兴趣的:(ACM)