蓝桥杯算法提高 连接乘积(完全c语言版)
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
192这个数很厉害,用它分别乘以1、2、3,会得到:
192 x 1 = 192
192 x 2 = 384
192 x 3 = 576
把这三个乘积连起来,得到192384576,正好是一个1~9的全排列
我们把上面的运算定义为连接乘积:
m x (1 … n) = k(其中m > 0 且 n > 1,对于上例,m = 192、n = 3、k = 192384576)
即k是把m分别乘以1到n的乘积连接起来得到的,则称k为m和n的连接乘积。
按字典序输出所有不同的连接乘积k,满足k是1~9的全排列
输出格式
每个k占一行
样例输出
显然,结果中应包含一行:
192384576
#include<stdio.h>
#include<math.h>
long long t[20]={0};//t要在排序函数里用,就放在外面了
void quicksort(int left,int right)//排序数组,递归快速排序
{
int i,j,k;
long long temp,m;
i=left;
j=right;
temp=t[i];//选出枢纽元,储存在temp中
if(left>right)
return;//跳出递归的关键
while(i<j)
{
while(t[j]>temp&&i<j)//从右边开始扫描
j--;
while(t[i]<temp&&i<j)//从左边开始扫描
i++;
if(i<j)
{
m=t[i];
t[i]=t[j];
t[j]=m;
}//将数值交换
}
quicksort(left,i-1);//调用自身
quicksort(i+1,right);
}
int jingwei(int a[]){//进位函数
int i=0;
int t=0;
int temp;
while(1){
temp=a[i];//保存当前位的值
a[i]=a[i]%10+t;//当前位的值等于当前位求余+上一位的进位
t=temp/10;//进位等于当前位/10
i++;//游标后移
if(t==0&&a[i]==0&&a[i-1]==0&&a[i+1]==0&&a[i+2]==0){//这里比较暴力,因为中间最多就3个0,所以也没想就直接乱写一通
break;
}
}
return i-1;//返回的i-1是存放数据的最后一个位置
}
int check(int a[]){//检查m是否到达最大值
if(a[0]==6&&a[1]==7&&a[2]==8&&a[3]==9/*&&a[4]==5&&a[5]==6&&a[6]==7&&a[7]==8&&a[8]==9*/)
//这里是表示m(a[])的遍历终点,因为n(kum)最小为2,所以k最大肯定是一个四位数和一个五位数的组合
//比如9999 19998,这里就举个例子这个显然不符合条件
//但是可以推断m(a[])最大就是9999,但是m里面肯定不能有重复的数,9999里面有多个9,所以暂且判断最大是9876
return 0;
else
return 1;
}
int main(){
int m[10]={0};//存放m
int n[10]={0};//存放n
int k[10]={0};//存放k
int i,j,l,p,r=0,s=0;//全是游标
int tum=1,num=0,kum=0;
while(check(m)==1){//大循环开始
m[0]=m[0]+1;//每次给个位+1
i=jingwei(m);//调用进位函数调整数m组并返回i为最后一个存放位置
/*for(p=i-1;p>=0;p--)
printf("%d ",m[p]);
printf("\n");
printf("**i=%d**\n",i);*/
/*for(j=0;j<9;i++){
printf("%d",m[j]);
}*///查bug
//printf("\n");
tum=1;
s=0;
/*for(p=i-1;p>=0;p--)
printf("*%d",m[p]);
printf("\n");*///查bug
while(1){//小循环1开始
for(j=0;j<9;j++){
n[j]=0;//n数组反复利用,怕出问题写了这个
}
for(j=0;j<=i-1;j++){
n[j]=m[j]*tum;//将m数组的0-i位依次乘tum 放进n数组里,tum的范围是2-9
}
l=jingwei(n);//进位函数 ,返回调整后的数组的存值的最后一个位置
/*
for(p=9;p>=0;p--)
printf("%d ",n[p]);
printf("\n"); *///查bug
l=jingwei(n); //调用进位函数调整数n组并返回l为最后一个存放位置
/*for(p=l-1;p>=0;p--)
printf("%d",n[p]);
printf("\n"); *///查bug
for(p=l-1;p>=0;p--){
k[s]=n[p];//把数组n的值给数组k
s++;//k数组的游标,游标s是没有重置的会一直加
}
tum++;
if(tum==10||s>=9)//如果k数组的存放到9位数或者n已经加到9了就跳出循环就跳出循环
break; //这里其实考虑到一开始其实k是到不了9位的
}//小循环1结束
/*for(p=0;p<=8;p++)
printf("%d ",k[p]);
printf("\n");*///查bug
num=0;
for(i=1;i<=9;i++){//判断k数组里面是否有1-9
for(j=0;j<9;j++){
if(k[j]==i&&k[j]!=0){
num++;
break;//防止重复计数,如果没break,9个1其实num还是能加到9
}
}
}
if(num==9&&s==9){//如果1-9都在k里而且s恰好等于9就是符合条件的了
//这里注意s==9是必须的,因为之前s其实是可以加到>9的
//比如k数组里本来是134578 269156但是只取9位就break了,变成了134578269是不符合条件的,但是由于我的算法原因,会判定为变成符合条件,所以我加了s==9来解决这个问题
for(i=0;i<9;i++){//后面的就很简单了,就是取数组元素转成十进制数,然后排个序输出
t[r]=t[r]+k[i]*pow(10,8-i);
}
r++;
}
}//大循环结尾
quicksort(0,r-1);//排序
for(i=0;i<r;i++)
printf("%lld\n",t[i]);
return 0;
}
c语言没有string所以我感觉写起来挺麻烦,但是有个同学问了我用c怎么写,我其实也是个菜鸡,就用死办法写了一个,其实还可以优化的是m ( a[] )遍历的时候如果有重复元素的可以直接给m加一跳过这个循环,其实可以快得多,一开始怕超时写了一个判断重复的函数,但是有点小bug所以没加进去,但是这样还是可以通过的,官网上cpu利用的数据居然是0,通过率是100
之后还会用c++或者java写一个,简易一些