PAT (Basic Level) Practice (中文)

PAT (Basic Level) Practice (中文)

1001 害死人不偿命的(3n+1)猜想

卡拉兹(Callatz)猜想:

对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1。卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……

我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?

#include<iostream>
int main()
{
    int n = 0, count = 0;
    std::cout<<"Please enter a number within 1000:" ;
    std::cin>> n ;
    while(n!=1){
	if(n%2==0){			//如果n是偶数
		n = n/2;		//砍掉一半
		count++;		//计数加1
    	}
	else{				//n是奇数
		n= (3*n+1)/2;	//把(3n+1)砍掉一半
		count++;		//计数器加1
	};
    	
    };
    std::cout<< n<<"需要" << count <<"步" <<std::endl;		//输出从 n 计算到 1 需要的步数。
    return 0;
}
1002
1003
1004 成绩排名

读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;
struct stu{		//定义stu类,包含姓名,学号,分数信息
    string sname;
    string sID;
    unsigned int scores = 0;	
    };
int main()
{
    unsigned int n = 0;	//输入的人数n
    stu stu1;
    vector<stu> stvec;	//容器stvec用来存放输入的学生的信息
    if(cin>>n){		//确保有数据输入
    	for(unsigned int i = 0; i<n; ++i){	
		cin>>stu1.sname>>stu1.sID>>stu1.scores;	//读入学生数据
		stvec.push_back(stu1);			//将读到的数据存入容器svec中
   	 }
    }

    for(int i = 0; i < n ; ++i){				//按分数将学生冒泡排序
	for(int j = 0; j < n - 1- i; ++j){
		if(stvec[j].scores > stvec[j+1].scores){
			stu temp = stvec[j];		//交换整个stu,全部学生信息
			stvec[j] = stvec[j+1];
			stvec[j+1] = temp;
		}
	}
     }

    cout<<stvec[stvec.size()-1].sname<<" "<<stvec[stvec.size()-1].sID<<" "<<endl;
    cout<<stvec[0].sname<<" "<<stvec[0].sID<<" "<<endl;		//输出

    
    
    system("pause");
    return 0;
}

1005 继续(3n+1)猜想
拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

void scin(int a, vector<int> &iv){	//完成题目要求的输入方式的函数
	cin>>a;
  	int b;
	for(int i = 0 ; i != a; ++i){
		if(cin>>b)
			iv.push_back(b);
	}
}

bool invec(const vector<int> &iv ,const int i, vector<int>::size_type &k){	//i是否在容器iv中,并隐式返回所在位置k
	for(decltype(iv.size() ) j = 0; j != iv.size(); ++j){
		if(iv[j] == i){
			k=j;
			return 1;
		}
	}
	return 0;
}


void callatz(vector<int> &iv, int n){		//找出一个数的卡拉兹‘衍生数’;
	while(n!=0 && n != 1){
		if(n%2 == 1){		//i是奇数
			n = (3*n + 1)/2;	//把(3n+1)砍一半存入iv
			iv.push_back(n);
		} else {			//i是偶数
			n = n/2;		//把n砍一半存入iv	
			iv.push_back(n);	
		}
	}
}

void  sort(vector<int> &iv){				//冒泡排序
	for(decltype(iv.size() ) j = 0; j != iv.size(); ++j){
		for(decltype(iv.size() ) i = 0; i != iv.size()-1; ++i){
			if(iv[i]<iv[i+1]){
				int temp = iv[i]; 
				iv[i]=iv[i+1]; 
				iv[i+1] = temp;
			}
		}
	}

}

int main()
{ 
    int sl = 0;
    vector<int> iv1,iv2,iv3;	//iv1,输入数据;iv2,卡拉兹衍生数据;iv3目标数据。
    scin(sl,iv1);

    vector<int>::size_type k;
    for(int i=0; i<iv1.size(); ++i){
	callatz(iv2,iv1[i]);		//找出第一个输入值的卡拉兹衍生数;
	for(decltype(iv2.size() ) j = 0; j != iv2.size(); ++j){	//遍历衍生数的容器
		if(invec (iv1,iv2[j],k)){			//衍生数是否已在输入的容器中
			iv1[k] = 0;				//若在,将其置0;
		}
	} 
  	iv2 = {};		//重置iv2的值,避免重复循环
}
    for(auto c : iv1){
	if(c != 0)
		iv3.push_back(c);		//把iv2中所有的非零值,即关键数字存入iv3
}

    sort(iv3);			//对iv3中元素进行排序
    for(auto c : iv3)
	cout<<c<<" ";		//范围for循环输出
    cout<<'\b'<<"end"<<endl;	//输出退格符,删除最后一个空格。 但这样写pat上测试不能通过,不知道为什么。。
 
    system("pause");
    return 0;
}
1006 换个格式输出整数
让我们用字母 B 来表示“百”、字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数。例如 234 应该被输出为 BBSSS1234,因为它有 2 个“百”、3 个“十”、以及个位的 4。
#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

void gsb(const int n, int &a,int &b,int &c){
	a = n % 10;	//个位
	b = (n/10)%10;	//十位
	c = n/100;	//百位
}

int main()
{ 
    int n = 0;
    int a,b,c;
    if(cin>>n && n<=999)
	gsb(n,a,b,c);
    for(int i = 0; i !=c; ++i)
	cout<<"B";
    for(int i = 0; i !=b; ++i)
	cout<<"S";
    for(int i = 0; i !=a; ++i)
	cout<<(i+1);
    system("pause");
    return 0;
}
1007 素数对猜想
让我们定义dn为dn=pn+1−pn,其中pi是第i个素数。显然有d1=1,且对于n>1有dn是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。

现给定任意正整数N(<10^5),请计算不超过N的满足猜想的素数对的个数

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

bool isprime(const int &m){		//求素数的算法需提高效率,最后一个测试会超时
    	if(m == 2) 
		return true;
	if(m % 2 == 0)
		return false;
	for(int i = 3; i < m-1; i += 2){
		if(m%i == 0)
			return false;
	}
	return true;
}

void element(vector<int> &pv, const int &m){	//把小于m的素数存入容器pv
	for(int i = 2; i <=m; ++i){
		if(isprime(i))
			pv.push_back(i);
	}
}


int main()
{ 
    int cnt=0;
    vector<int> ev{};
    int n = 0;
    if(cin>>n)
	    element(ev,n);
    for(auto it = ev.begin(); it != ev.end()-1; ++it){
	    if(*(it+1) - *it == 2)
		    ++cnt;
}
    cout<<cnt<<endl;
    return 0;
}
1008 数组元素循环右移问题
	一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A~0~A~1~…A~N-1~)变换为(A~N−M~⋯A~N−1~A~0~A​~1​​~ ⋯A~N−M−1~)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

思路:可以把数组看作由下标N-M-1分割的两部分组成,N-M-1之后的AN-M到AN-1和N-M-1之前的A0到AN-M-1
AN−M⋯AN−1 A0A​1​​ ⋯AN−M−1

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

int main()
{ 
    size_t arrs = 0;		//定义数组大小
    cin>>arrs;		//输入数组大小
    int arr[arrs];		//定义数组,书上说数组的维度必须是常量表达式(constexpr),但。。
    size_t m = 0;
	cin>>m;		//输入m的值
	if(m>arrs)		//循环右移,要考虑到位移值m大于数组长度的情况
		m = m % arrs;
	
	int a;
	int i = 0;
	while(cin>>a){
		arr[i] = a;		//读入数组的值
		++i;
	} 
	
	vector<int> pm {};		//定义容器负责存储数组的前arr-m个数
	vector<int> bm {};		//容器bm负责存储数组剩下的 m 个数
	for(size_t i = 0; i < arrs-m ; ++i){		//把数组的前arr - m个数存入pm
		pm.push_back(arr[i]);	
	}
	//cout<<"pm: ";
	//for(auto c:pm)
		//cout<<c<<" ";
	//cout<<endl;
	for(size_t i = arrs-m; i<arrs ; ++i){	//把数组剩下的 m 个数存入bm
		bm.push_back(arr[i]);
	}
	//cout<<"bm: ";
	//for(auto c:bm)
		//cout<<c<<" ";
	//cout<<endl;
	
    for(size_t i = 0; i<m; ++i){		 
    	arr[i] = bm[i];
	}
	for(size_t i = m,j=0; i<arrs&&j<pm.size(); ++i,++j){
		arr[i] = pm[j];
	}
	
	for(size_t i = 0; i<arrs; ++i){
		cout<<arr[i]<<" ";
	}
	cout<<endl;
 
    system("pause");
    return 0;
}

1009 说反话

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出

#include<iostream>
#include<vector>
#include<string>

using namespace  std;

int main(){
    vector<string> sv;
    string s;
    while(cin>>s){
        sv.push_back(s);
    }
    for(int i=sv.size()-1;i>=0;--i){	//逆序遍历输出即可
        cout<<sv[i];
        if(i!=0)
            cout<<" ";
    }
    cout<<endl;
    return 0;
}
1010 一元多项式求导

设计函数求一元多项式的导数。

#include<iostream>
#include<vector>

using namespace std;

int main(){
    vector<int> iv;
    vector<int> cv;
    int a;
    while(cin>>a){
        iv.push_back(a);
    }
    for(decltype(iv.size()) i=0;i<iv.size()-1;i+=2){
        if(iv[i+1]!=0){
            cv.push_back(iv[i]*iv[i+1]);
            cv.push_back(iv[i+1]-1);
        } else if(iv.size() == 2) {		//注意考虑题目中提到的一种特殊情况,即求导后位零多项式的情况 
            cv.push_back(0);
            cv.push_back(0);
        }
    }
    for(decltype(cv.size()) i=0;i<cv.size();++i){
        cout<<cv[i];
        if(i!=cv.size()-1)
            cout<<" ";
    }
    cout<<endl;
    return 0;
}
1011 A+B 和 C

给定区间 [−231​​ ,231] 内的 3 个整数 A、B 和 C,请判断 A+B 是否大于 C

#include<iostream>
#include<vector>

using namespace std;

int main(){
	int count;
	cin>>count;
	vector<long> iv;		//注意用long,int只有16位,会溢出
	long a;
	for(int i=0;i<count;++i){
		for(int j=0;j<3;++j){
            cin>>a;
			iv.push_back(a);
		}
		if(iv[0]+iv[1]>iv[2]){
			cout<<"Case #"<<i+1<<": true"<<endl;
		} else {
			cout<<"Case #"<<i+1<<": false"<<endl;
		}
		iv={};
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值