• 2016年蓝桥杯B组C/C++省赛(预选赛)题目解析


    2016年蓝桥杯B组C/C++

    点击查看2016年蓝桥杯B组省赛试题(无答案版)

    ![](https://img2018.cnblogs.com/blog/1454456/201811/1454456-20181125135015550-30277785.png)

    第一题:煤球数目 题解

    有一堆煤球,堆成三角棱锥形。具体:
    第一层放1个,
    第二层3个(排列成三角形),
    第三层6个(排列成三角形),
    第四层10个(排列成三角形),
    ....
    如果一共有100层,共有多少个煤球?

    请填表示煤球总数目的数字。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    题解:171700 数列求和

            int acc=0,num=0; 
            for(int i=1;i<=100;i++){
                acc += i; 
                num += acc; 
            }
            cout<<num<<endl;
    

    第二题:生日蜡烛

    某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。

    现在算起来,他一共吹熄了236根蜡烛。

    请问,他从多少岁开始过生日party的?

    请填写他开始过生日party的年龄数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    题解:26 枚举,等差数列求和

    #include<iostream>
    using namespace std;
    
    int main(){
    	int n;
    	int sum = 1;
    
    	//枚举 开始过生日得年龄j 过了几次i 
    	for(int i=1;i<=111;i++){
    		for(int j=1;j<=111;j++){
    			//等差数列求和 a1 = i*j(开始过生日那年岁数,也就是吹蜡烛得数量,公差d=1,和等于236) 
    			if(i*j+1.5*(i*i) - 1.5*i == 236){
    				cout<<"i="<<i<<" "<<" j="<<j<<endl;
    			}
    		}
    	}
    	int d = 26;
    	for(int i=1;i<=11;i++){
    		sum+=d;
    		cout<<sum<<endl;
    		d++;
    	}
    }
    //26岁过的生日 
    

    第三题:凑算式

         B      DEF
    A + --- + ------- = 10
         C      GHI
    

    (如果显示有问题,可以参见【图1.jpg】)

    这个算式中AI代表19的数字,不同的字母代表不同的数字。

    比如:
    6+8/3+952/714 就是一种解法,
    5+3/1+972/486 是另一种解法。

    这个算式一共有多少种解法?

    注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

    题解一:29 暴力枚举

    #include<iostream>
    using namespace std;
    
    int main(){
    	int sum = 0;
    	//解法一:暴力枚举 枚举每一个位置的值 
    	for(int a = 1;a<=9;a++){
    		for(int b = 1;b<=9;b++){
    			if(b==a) continue;
    		for(int c = 1;c<=9;c++){
    			if(c==b || c==a) continue;
    		for(int d = 1;d<=9;d++){
    			if(d==c || d==b || d==a) continue;
    		for(int e = 1;e<=9;e++){
    			if(e==d || e==c || e==b || e==a) continue;
    		for(int f = 1;f<=9;f++){
    			if(f==d || f==c || f==b || f==a ||f==e) continue;
    		for(int g = 1;g<=9;g++){
    			if(g==d || g==c || g==b || g==a ||g==e||g==f) continue;
    		for(int h = 1;h<=9;h++){
    			if(h==d || h==c || h==b || h==a ||h==e||h==f || h==g) continue;
    		for(int i = 1;i<=9;i++){
    			if(i==d || i==c || i==b || i==a ||i==e||i==f || i==g || i==h) continue;
    			int ghi = g*100+h*10+i;
    			int def = d*100+e*10+f;
    			//解决除法精度问题 需要将除数乘以0.1 
    			if( a+b*1.0/c+def*1.0/ghi==10 ){
    				sum++;
    				cout<<"a= "<<a<<"  "<<"b= "<<b<<"  "<<"c= "<<c<<"  def="<<def<<"  ghi="<<ghi<<endl;
    			}
    		}
    		}
    		}
    		}
    		}
    		}
    		}
    		}
    		}
    		cout<<sum<<endl;
    } 
    //29种 
    

    题解二:29 dfs深搜:dfs全排列类型题

    #include<iostream>
    using namespace std;
    
    //dfs:9个数做全排列 不使用相同数字 
    
    int a[9]={0};
    int ans=0;
    bool judge(int *a)//判断是否算式和为10
    {
        double x=a[0]+a[1]*1.0/a[2]+(a[3]*100+a[4]*10+a[5])*1.0/(a[6]*100+a[7]*10+a[8]);
        if(x==10.0) return true;
        return false;
    }
    
    bool check(int index)//检测a[index]是否有重复
    {
    	//检查前index-1个数是否与当前数重复 
        for(int i=index-1;i>=0;i--)
        {
            if(a[i]==a[index]) return false;
        }
        return true;
    }
    
    //就是最基本的9个数全排列,在dfs结束条件里用judge()做判断
    void dfs(int index)
    {
    	//结束条件中调用judge()判断是否满足条件 
        if(index>8)
        {
            if(judge(a))
            ans++;
            return;
        }
        
        //枚举1~9这10个数 
        for(int i=1;i<=9;i++)
        {
            a[index]=i;//当前位置的值置为i 
            //check()函数判断当前位置是否用了 前面用过的重复的数字 
            if(check(index))
            { 
                dfs(index+1);//没有重复,则枚举下一个位置的数 
            }
        }
    }
    
    int main()
    {
        dfs(0);
        cout<<ans<<endl;
        return 0;
    }
    

    第四题:快速排序

    排序在各种场合经常被用到。
    快速排序是十分常用的高效率的算法。

    其思想是:先选一个“标尺”,
    用它把整个队列过一遍筛子,
    以保证:其左边的元素都不大于它,其右边的元素都不小于它。

    这样,排序问题就被分割为两个子区间。
    再分别对子区间排序就可以了。

    下面的代码是一种实现,请分析并填写划线部分缺少的代码。

    题解:swap(a,j,p);

    选定第一个表示a[p]p=0,即第一个元素,i从数组前面向后移,j从数组后面向前移动。i停在比a[p]大的位置,j停在比a[p]小的位置,交换他俩的位置,到i>=j的时候停止移动,这时候,p位置到j位置是小于a[p]的元素,j+1位置到r位置都是大于a[p]的元素,该段代码的目的是标尺的左边都是小于它的数,右边都是大于它的数,所以要将p位置的元素和j位置的元素进行交换。

    考察调试程序BUG的能力,步骤如下:

    ①理解题干,从题干中找出发点,写出正确的程序结果

    ②对照程序输出结果进行逻辑推测

    ③观察程序代码找出漏洞

    #include <stdio.h>
    
    void swap(int a[], int i, int j)
    {
    	int t = a[i];
    	a[i] = a[j];
    	a[j] = t;
    }
    
    //快速排序 严版数据结构中的做法  以第一个元素为枢轴 两边排 
    int partition(int a[], int p, int r)
    {
    	int i = p;
    	int j = r + 1;
    	int x = a[p];//以第一个元素为枢轴
    	while(1){
    		while(i<r && a[++i]<x);
    		while(a[--j]>x);
    		if(i>=j) break;
    		swap(a,i,j);
    	}
    	swap(a,j,p);//枢轴元素存放到最终位置j上 
    	return j;
    }
    
    void quicksort(int a[], int p, int r)
    {
    	if(p<r){
    		int q = partition(a,p,r);
    		quicksort(a,p,q-1);
    		quicksort(a,q+1,r);
    	}
    }
    
    int main()
    {
    	int i;
    	int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
    	int N = 12;
    	quicksort(a, 1, N-1);
    	for(i=1; i<N; i++) printf("%d ", a[i]);
    	printf("
    ");
    	return 1;
    }
    

    第五题:抽签

    X星球要派出一个5人组成的观察团前往W星。
    其中:
    A国最多可以派出4人。
    B国最多可以派出2人。
    C国最多可以派出2人。
    ....

    那么最终派往W星的观察团会有多少种国别的不同组合呢?

    下面的程序解决了这个问题。
    数组a[] 中既是每个国家可以派出的最多的名额。
    程序执行结果为:

    DEFFF
    CEFFF
    CDFFF
    CDEFF
    CCFFF
    CCEFF
    CCDFF
    CCDEF
    BEFFF
    BDFFF
    BDEFF
    BCFFF
    BCEFF
    BCDFF
    BCDEF
    ....
    (以下省略,总共101行)
    

    题解:f(a,k+1,m-j,b);

    1.读题后看程序,不难看出填空位置是要填写递归语句,
    2.而第一个参数和最后一个参数不需要改变,
    根据递归退出条件和给出的常量可以推断出m表示还需要组多少人。k表示队伍编,因此每次操作一个队伍,
    所以每次递归的时候k要加一,而m需要减少当前已经选的人数。

    #include <stdio.h>
    #include<iostream>
    #define N 6
    #define M 5
    #define BUF 1124
    using namespace std;
    
    void f(int a[], int k, int m, char b[])
    {
    	int i,j;
    	//到达最后一个国家时 要是名额已满 打印b 
    	if(k==N){
    		b[M] = 0;
    		if(m==0) printf("%s
    ",b);
    		return;
    	}
    
    	//a[k]表示当前第k国所人数总数 
    	for(i=0; i<=a[k]; i++){
    		//第k国所有人都作为参加人员 
    		for(j=0; j<i; j++){
    //			int d = M-m+j; //调试理解M-m+j 
    //			if(k==0)cout<<d<<endl;
    			//理解M-m+j
    			b[M-m+j] = k+'A';  //
    		}
    //		cout<<b<<endl;//调试打印字符数组b 
    		f(a,k+1,m-i,b);//m-j还剩几个人。剩下几人呢? 当前选了第i个人 i++,所以还剩下m-i个人,比如i=0 i++ 还剩下 5-1个 
    	}
    }
    
    int main()
    {
    	int a[N] = {4,2,2,1,1,3};//各国人数
    	char b[BUF];//存放结果 
    	f(a,0,M,b);//调用函数 
    	return 0;
    }
    

    第六题:方格填数

    如下的10个格子

       +--+--+--+
       |  |  |  |
    +--+--+--+--+
    |  |  |  |  |
    +--+--+--+--+
    |  |  |  |
    +--+--+--+
    

    (如果显示有问题,也可以参看【图1.jpg】)

    填入0~9的数字。要求:连续的两个数字不能相邻。
    (左右、上下、对角都算相邻)

    一共有多少种可能的填数方案?

    请填写表示方案数目的整数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    题解:1580 dfs回溯

    从坐标(0,1)开始dfs枚举填数,且不能使用相同数字(v数组作标记是否使用),相邻格子数字也不能相邻(使用isvalid()函数做判断),当前状态搜索完后,回溯恢复原状态(使用过的数置为未使用)

    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int mymap[3][4] = {{-222,-4,-6,-8},{-10,-12,-14,-16},{-18,-20,-22,-2222}};
    int ans = 0;
    int v[10]; //判断数是否用过 
    
    
    //检测 上 下 左 右 左上 右上 左下 右下 共8个方向的值与当前坐标上的值是否相邻
    bool isvalid(int x,int y,int k){
    	bool flag = true;
    	if(x-1>=0 && abs(mymap[x-1][y] - k) == 1){
    		flag = false;
    	}
    	if(x+1<=2 && abs(mymap[x+1][y] - k) == 1){
    		flag = false;
    	}
    	if(y-1>=0 && abs(mymap[x][y-1] - k) == 1){
    		flag = false;
    	}
    	if(y+1<=3 && abs(mymap[x][y+1] - k) == 1){
    		flag = false;
    	}
    	if(x-1>=0 && y-1>=0 && abs(mymap[x-1][y-1] - k) == 1){
    		flag = false;
    	}
    	if(x-1>=0 && y+1<=3 && abs(mymap[x-1][y+1] - k) == 1){
    		flag = false;
    	}
    
    	if(x+1<=2 && y+1<=3 && abs(mymap[x+1][y+1] - k) == 1){
    		flag = false;
    	}
    	if(x+1<=2 && y-1>=0 && abs(mymap[x+1][y-1] - k) == 1){
    		flag = false;
    	}
    	return flag;
    }
    
    void dfs(int x,int y){
    	
    	if(x==2 && y==3){
    		ans++;
    		return;
    	}
    	
    	//下一步dfs的坐标 
    	int nextx = x; 
    	int nexty = y+1;
    
    	for(int k=0;k<=9;k++){
    		if( !v[k] && isvalid(x,y,k) ){
    			mymap[x][y] = k;
    			v[k] = 1;//当前数已经用过 
    			
    			//坐标换行 
    			if(y==3 && x<2){
    				 nextx = x+1;
    				 nexty = 0;
    			}
    			
    			dfs(nextx,nexty);
    			v[k] = 0;//什么时候要回溯?——后面不同坐标dfs的条件中要用到当前v数组的值 和 mymap的值 
    			mymap[x][y] = -2;
    		}
    	}
    
    
    }
    
    void init(){
    	for(int i=0;i<=2;i++){
    		for(int j=0;j<=3;j++){
    			mymap[i][j] = -2;
    		}
    	}
    	for(int i=0;i<=9;i++){
    		v[i] = 0;
    	}		
    } 
    
    int main(){
    	dfs(0,1); 
    	cout<<ans<<endl;
    }
    //1580
    

    第七题:剪邮票

    如【图1.jpg】,

    有12张连在一起的12生肖的邮票。
    现在你要从中剪下5张来,要求必须是连着的。
    (仅仅连接一个角不算相连)
    比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

    请你计算,一共有多少种不同的剪取方法。

    请填写表示方案数目的整数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    题解:116 暴力枚举选出5个数 + dfs判断连通性

    #include<iostream>
    using namespace std;
    
    //暴力枚举选出5个数 dfs判断是否连通
    
    int arr[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};//题目中的邮票矩阵 
    bool visited[13] = {false};//判断数是否访问过 
    bool selected[13] = {false};//判断数是否选中 
    int ans = 0;//统计总数 
    int dr[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};//方向数组 
    
    //检查dfs后当前选的5个值是否满足条件 
    bool check(int a,int b,int c,int d,int e){
    	if(visited[a] == false){
    		return false;
    	}
    	if(visited[b] == false){
    		return false;
    	}
    	if(visited[c] == false){
    		return false;
    	}
    	if(visited[d] == false){
    		return false;
    	}
    	if(visited[e] == false){
    		return false;
    	}
    	return true;
    }
    
    //判断当前所选的5个数的连通性
    void dfs(int a){
    	
    	//找到数值为a时 在邮票矩阵中对应的坐标 
    	int x,y;
    	for(int i=0;i<3;i++){
    		for(int j=0;j<4;j++){
    			if(arr[i][j] == a){
    				x = i;
    				y = j;
    				break;
    			}
    		}
    	}
    	
     	//开始枚举四个方向搜索 判断连通性
    	int nextx,nexty;
    	for(int i=0;i<4;i++){
    		nextx = x + dr[i][0];
    		nexty = y + dr[i][1];
    		//越界判断 这种情况要跳过 
    		if( nextx >2 || nexty>3 || nextx<0 || nexty<0 ){
    			continue;
    		}
    		int d = arr[nextx][nexty];//下一个遍历的点 
    	
    		if( !visited[d] && selected[d]){
    			visited[d] = true;//下一个遍历的点设置成访问过 
    			dfs(d);//遍历下一个点  
    		}
    	}	
    }
    
    int main(){
    	//毕竟只是填空题 数据量也小 暴力一下 
    	//这里递增枚举 避免重复 
    	for(int a = 1;a<=8;a++){
    		for(int b = a+1;b<=9;b++){
    			for(int c = b+1;c<=10;c++){
    				for(int d=c+1;d<=11;d++){
    					for(int e=d+1;e<=12;e++){
    						
    						//清空visited数组 
    						for(int i=1;i<=12;i++){
    							visited[i] = false;
    						}
    
    						//selected数组置为已经选择 
    						selected[a] = true;
    						selected[b] = true;
    						selected[c] = true;
    						selected[d] = true;
    						selected[e] = true;
    						
    						visited[a] = true;//dfs搜索的起点设置成访问过						
    						dfs(a);//开始搜索起点 
    						
    						//dfs搜完后清空selected数组 
    						selected[a] = false;
    						selected[b] = false;
    						selected[c] = false;
    						selected[d] = false;
    						selected[e] = false;
    						
    						//检查是否满足连通:遍历visited数组 连通的条件是visited数组的5个数在dfs搜索的时候全部访问过 
    						bool flag = false;
    						flag = check(a,b,c,d,e);
    						if(flag){
    							ans++;
    							cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<e<<endl;
    						}				
    					}
    				}
    				
    			}
    		} 
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    第八题:四平方和

    四平方和定理,又称为拉格朗日定理:
    每个正整数都可以表示为至多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 为联合主键升序排列,最后输出第一个表示法

    程序输入为一个正整数N (N<5000000)
    要求输出4个非负整数,按从小到大排序,中间用空格分开

    例如,输入:
    5
    则程序应该输出:
    0 0 1 2
    
    再例如,输入:
    12
    则程序应该输出:
    0 2 2 2
    
    再例如,输入:
    773535
    则程序应该输出:
    1 1 267 838
    

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 3000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

    题解:法一暴力枚举,法二枚举+查表

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    
    int main(){
    	int t;
    	cin>>t;
    	//暴力枚举 4层循环 
    	for(int a=0;a*a<t;a++){
    		for(int b=a;b*b<t;b++){
    			for(int c=b;c*c<t;c++){
    				for(int d=c;d*d<t;d++){
    					if(a*a + b*b + c*c + d*d == t){
    						printf("%d %d %d %d
    ",a,b,c,d);
    						return 0; 
    					}
    				}
    			}
    		}
    	}
    	return 0;
    } 
    //枚举,后面再优化 
    

    方法二:unordered_map查表

    #include<iostream>
    #include<unordered_map> 
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    
    unordered_map<int,int> mymap;
    
    int main(){
    //	枚举a*a + b*b   查表查找是否有c*c + d*d 满足 n-a*a-b*b == c*c + d*d 
    	long long  n;
    	cin>>n;
    	long long a,b,c,d,e;
    	//生成表 
    	for(c = 0;c*c<=n;c++){
    		for(d=c;c*c+d*d<=n;d++){
    			if(mymap.find(c*c+d*d) == mymap.end()){
    				mymap[c*c+d*d] = c;//存放c的值  c*c-d*d:c 
    			}
    		}
    	}
    	//枚举a和b 
    	for(a = 0;a*a*4<=n;a++){
    		for(b=a;b*b*2<=n;b++){
    			//查找表 查看mymap表中是否有 n-a*a-b*b这个值 
    			if(mymap.find(n-a*a-b*b) != mymap.end()){
    				c = mymap[n-a*a-b*b];
    				d = int(sqrt(n-a*a-b*b-c*c));
    				cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
    				return 0;
    			}
    		}
    	} 
    	return 0;
    } 
    

    第九题:交换瓶子

    有N个瓶子,编号 1 ~ N,放在架子上。

    比如有5个瓶子:
    2 1 3 5 4

    要求每次拿起2个瓶子,交换它们的位置。
    经过若干次后,使得瓶子的序号为:
    1 2 3 4 5

    对于这么简单的情况,显然,至少需要交换2次就可以复位。

    如果瓶子更多呢?你可以通过编程来解决。

    输入格式为两行:
    第一行: 一个正整数N(N<10000), 表示瓶子的数目
    第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

    输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。

    例如,输入:
    5
    3 1 2 5 4
    
    程序应该输出:
    3
    
    再例如,输入:
    5
    5 4 3 2 1
    
    程序应该输出:
    2
    

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 1000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

    题解:模拟法,有点像冒泡排序

    n-1层循环 比较当前第i个 与 [i+1,n]即i后面的数,找到一个比当前i值小的最小的元素,记录下标交换位置

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    
    int a[10010];
    int ans = 0;
    
    int main(){
    	int n;
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	//n-1层循环 找到比当前元素小的最小的一个数的下标 交换位置 
    	for(int i=1;i<n;i++){
    		int d = a[i];
    		int min = 0x3f3f3f3f;
    		int minindex = -1;
    		
    		//从i+1开始找 找到比当前元素小的最小的一个数的下标
    		for(int j=i+1;j<=n;j++){
    			if(a[j] < a[i] && a[j]<min){
    				min = a[j];
    				minindex = j;
    			}
    		}
    		//交换位置  
    		if(a[i] != a[minindex] && minindex!=-1){
    			ans++;
    			swap(a[i],a[minindex]);
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    } 
    

    第十题:最大比例

    X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
    并且,相邻的两个级别间的比例是个固定值。
    也就是说:所有级别的奖金数构成了一个等比数列。比如:
    16,24,36,54
    其等比值为:3/2

    现在,我们随机调查了一些获奖者的奖金数。
    请你据此推算可能的最大的等比值。

    输入格式:
    第一行为数字N,表示接下的一行包含N个正整数
    第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额

    要求输出:
    一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数

    测试数据保证了输入格式正确,并且最大比例是存在的。

    例如,输入:
    3
    1250 200 32
    
    程序应该输出:
    25/4
    
    再例如,输入:
    4
    3125 32 32 200
    
    程序应该输出:
    5/2
    
    再例如,输入:
    3
    549755813888 524288 2
    
    程序应该输出:
    4/1
    

    资源约定:
    峰值内存消耗 < 256M
    CPU消耗 < 3000ms

    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

    注意: main函数需要返回0
    注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
    注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

    提交时,注意选择所期望的编译器类型。

    题解:通过本题学会使用gcd求最大公约数,化简分数,分数比较大小。

    #include<iostream>
    #include<algorithm> 
    using namespace std;
    
    //复杂度o(n^2) 能过100%的数据 
    //思路: 分析序列的比例关系——借用gcd最大公约数化简分数,比较分数时分母通分后比较分子, 
    //借用多个数组存放数据
    
    bool cmp(long long a,long long b){
    	return a>b;
    }
    
    long long arr[10010];
    long long p1[10010],p2[10010];
    long long n;
    
    long long gcd(long long a,long long b){
        if(b==0){
            return a;
        }
        return gcd(b,a%b);
    } 
    
    int main(){
    	cin>>n;
    	for(long long i=0;i<n;i++){
    		cin>>arr[i];
    	}
    	sort(arr,arr+n,cmp);
    	//54 36 16
    	//3/2 9/4  
    	 
    	//存放比例( 数/最大公约数 ) 
    	for(long long i=0;i<n-1;i++){
    		long long d = gcd(arr[i],arr[i+1]);
    		p1[i] = arr[i]/d; 
    		p2[i] = arr[i+1]/d; 
    		//p[i]/p[i+1]就是相邻元素间的比例 共n-1个下标n-2 
    	}
    	
    	long long num1,num2,temp = 0x3f3f3f3f,final1,final2;
    	//遍历两个数组
    	for(long long i=0;i<n-2;i++){
    		for(long long j=i+1;j<n-1;j++){
    			//通分 比如3/2 9/4  通分成 12/8和18/8 
    			if(p1[i] * p2[j] == p1[j] * p2[i]){
    				//两个相等时 p1 == p2 
    				num1 = p1[i];
    				num2 = p2[i];
    			}
    
                if(p1[i]*p2[j]>p1[j]*p2[i]){   
                    num1=p1[i]/p1[j];
                    num2=p2[i]/p2[j];
                }
                else if(p1[i]*p2[j]<p1[j]*p2[i]){
                    num1=p1[j]/p1[i];
                    num2=p2[j]/p2[i];
    			}
    			if(num1*1.0/num2 < temp){
    				temp  = num1*1.0/num2;
    				final1 = num1;
    				final2 = num2;
    			}
    		}
    	}
    	cout<<final1<<"/"<<final2<<endl;
    	return 0;
    }
  • 相关阅读:
    Android之Parcel
    Android常用的IPC通信
    Android之Surface绘制原理
    Android之Surface
    Android之SurfaceFlinger服务
    Android Service(服务)
    Android Service进阶之路
    Android之UI线程启动
    Android之Activity显示原理
    python17-Django进阶
  • 原文地址:https://www.cnblogs.com/fisherss/p/10028572.html
Copyright © 2020-2023  润新知