蓝桥杯PREV-3 全排列暴力技巧枚举

11 篇文章 0 订阅
3 篇文章 0 订阅

这道题思路上就是枚举,但是枚举过程为了不超时,需要对一部分的数字进行剪枝,这里不同的题目,技巧不同而且多样,这里我用网上看到的想法。

主要思路:对1-9 9个数进行全排列,这里直接用stl的next_permutation实现。然后对于每一个排列情况,遍历所有a可能的情况(与位数有关)。当a为x位时,遍历bc的可能情况,满足条件则计数。

剪枝:根据a+b/c=n得出b=(n-a)*c,于是可以推出b的最后一位应该是(n-a)*num[8](最后一位只与c的最后一位有关,而且当排列确定了以后b的最后一位也确定),而且由b>c,得出b的最后一位起码应该在去掉a后的中部位置,所以从中部开始向后遍历,如果找到了b的最后一位也就确定了a b c,再判断是否满足必要的条件;如果找不到则可以直接换a的下一个位置的情况。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-6;
int num[]={1,2,3,4,5,6,7,8,9};
int dig,lft,up,down,dig1,cnt,n,ans,temp;

bool vis;

int compute(int dg,int st){
    int ans=0;
    for(int i=dg-1;i>=0;i--){
        ans+=round(pow(10,i))*num[st++];
    }
    return ans;
}

int computedig(int n){///计算位数
    int cnt=0;
    do{
        cnt++;
        n/=10;
    }while(n);
    return cnt;
}

int main(){
    //freopen("out.txt","w",stdout);
    while(scanf("%d",&n)!=EOF){
        dig=computedig(n);
        cnt=0;///记录可能个数
        sort(num,num+9);
        do{
            for(int i=1;i<=dig;i++){///遍历lft所有可能的位数
                lft=compute(i,0);///位数和起始的下标位置
                if(lft>=n)
                    break;
                int mid=ceil((9-i)/2);///找到中间位置
                for(int j=i+mid-1;j<=8;j++){
                    if(num[j]==((n-lft)*num[8])%10){///如果后面又出现b的最后一位
                        dig1=j-i+1;///确定b
                        up=compute(dig1,i);
                        //cout<<up<<endl;
                        down=compute(9-i-dig1,j+1);///确定c
                        //cout<<"d:"<<down<<endl;
                        if(down==0)///防止分母为0
                            continue;
                        ans=up/down;
                        if(ans&&!(up%down)&&(ans==n-lft))///满足条件计数
                            cnt++;
                    }
                }
            }
        }while(next_permutation(num,num+9));
        printf("%d\n",cnt);
    }
    return 0;
}

然后打蓝桥杯要养成一个习惯,。即便想不到最优的算法,暴力也要打一波,这样才会有分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值