【PTA刷题】乙级 1005 To 1025

本文精选了多个算法竞赛题目,包括3n+1猜想、数组循环右移、一元多项式求导等,详细解析了各种算法思路和编程技巧,如哈希表应用、大数运算、链表反转等,适合算法学习者深入理解并实践。

B1005.继续(3n+1猜想)
**思路:**用哈希表的思想(实际上就是个简单数组,因为没有用到哈希函数),将读入的数字算一个数列出来,然后访问哈希表中的脚标。访问过一次则将表的值改为1. 然后再检索输入的数字里面哪个数字对应的哈希表中的数字是0,把它输出。

需要注意的是:
1.数组的大小一开始开的不够大,挂了两个测试点。(以后往大了开,炸内存了再改小)
2.一个老问题,Vector的erase和for循环时要注意。
例子如下:

	for (auto iter = Result.begin(); iter != Result.end(); )//循环和erase一起用要注意
	{
		if (Hash[*iter] != 0)
		{
			auto tmp = iter;
			iter = Result.erase(tmp);//指针保持没变,相当于中间抽掉一个数
		}
		else
			iter++;
	}
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int MaxNum = 10000;
int Hash[MaxNum];
vector<int> vec;
vector<int> Result;

void Mark(int K)//根据标记Callatz数组
{
	vec.clear();//清除上次使用痕迹
	while (K != 1)
	{
		if (K % 2 == 1)//奇数
			K = (3 * K + 1) / 2;
		else
			K = K / 2;
		
		vec.push_back(K);
	}

}

bool cmp(int a ,int b)
{
	return a > b;
}

int main()
{	
	for (int i = 0; i < 10000; i++)//初始化
		Hash[i] = 0;

	int N, K;
	cin >> N;
	for (int i = 0; i < N; i++)
	{
		cin >> K;
		Result.push_back(K);//暂存结果
		if (Hash[K] != 1)//没有访问过
		{	
			Mark(K);
			for (int j = 0; j < vec.size(); j++)//标记此时出现过的数
				Hash[vec[j]] = 1;
		}
	}
	/*以上,标记完成*/
	sort(Result.begin(), Result.end(),cmp);

	int flag = 0;
	for (int i = 0; i < Result.size(); i++)
	{
		if (Hash[Result[i]] == 0)
		{
			if (flag == 1) cout << " ";
			cout << Result[i];
			flag = 1;
		}
	}

	return 0;
}

B1006.换个格式输出整数
签到题

/*B1006-换个格式输出*/
#include <iostream>

using namespace std;


int main()
{
	int Num;
	int Bai, Shi, Ge;
	cin >> Num;
	Bai = Num / 100;
	if (Bai != 0)
		for (int i = 0; i < Bai; i++)
			cout << "B";
	
	Num = Num % 100;//删掉百位
	Shi = Num / 10;
	if (Shi != 0)
		for (int i = 0; i < Shi; i++)
			cout << "S";

	Num = Num % 10;//删掉十位
	Ge = Num;
	for (int i = 1; i <= Ge; i++)
		cout << i;

	return 0;
}

B1007. 素数对猜想
思路:先写一个IsPrime,然后从i=5开始一直遍历到N,然后判断I 和I-2是否同时为素数。

需要注意的是:
1.注意小于号还有小于等于号的应用情况。
2.IsPrime的写法中,中2开始,到根号a,如果a能被任何一个i整除,则a就不是素数了

/*B1007-s素数对猜想*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

const int MaxNumber = 10e5;

bool IsPrime(int a)
{
	for (int i =  2; i*i <= a; i++)
		if (a % i == 0)
			return false;

	return true;
}

int main()
{
	int Num, i ;
	cin >> Num;

    if (Num < 5)
	{
		cout << 0;
		return 0;
	}
	int cnt = 0;
	for (i = 5; i <= Num; i++)
	{
		if (IsPrime(i - 2) && IsPrime(i))
			cnt++;
	}
	cout << cnt;

	return 0;


}

B1008.数组循环右移问题

思路: 我不开一个临时数组不会做,完全看题解做的。 题解是用了一个巧妙的规律,先将整个数组倒置,然后导致前M个,再倒置从M到N的数据,最后神奇发现就是右移的结果。

需要注意的是:
1.M大于N的时候,有M%N,因为大于N的倍数的移动都是多余的。
2.用reverse()来实现倒置,在algorithm中

/*B1008-数组元素循环右移问题*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

const int MaxN = 101;


int main()
{
	int N, M;
	cin >> N>> M;

	vector<int> vec(N);
	for (int i = 0; i < N; i++)
		cin >> vec[i];

	M = M % N;
	if (M != 0)
	{
		reverse(vec.begin(), vec.begin() + N);
		reverse(vec.begin(), vec.begin() + M);
		reverse(vec.begin() +  M, vec.begin() + N);
	}
	
	for (int i = 0; i < N; i++)
	{
		cout << vec[i];
		if (i != N - 1) cout << " ";
	}

	return 0;
}

B1009.说反话
思路:签到题,直到cin的读取是一个空格一个空格读取的就行。

/*B1009-说反话*/
#include <iostream>
#include <string>
#include <stack>
using namespace std;


int main()
{
	string str;
	stack<string> S;
	
	while (cin >> str)
		S.push(str);

	while (!S.empty())
	{
		cout << S.top();
		S.pop();
		if (S.size() != 1)
			cout << " ";
	}
	
	return 0;
}

B1010.一元多项式求导
签到题

/*B1010-一元多项式求导*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>
#include <stack>
using namespace std;

vector<int> result;

int main()
{
	int Xishu, Zhishu;
	while (cin >> Xishu >> Zhishu)
	{
		Xishu *= Zhishu;
		if (Xishu != 0) result.push_back(Xishu);
		Zhishu--;
		if (Zhishu >= 0) result.push_back(Zhishu);

	}
	if (!result.empty())
	{
		cout << result[0];
		for (int i = 1; i<result.size(); i++)
			cout << " " << result[i];
	}
	else
		cout << 0 << " " << 0;


	return 0;
}

B1011.A+B和C
long long int 可以表示64位(有符号63位)所以直接用longlong就好了不用写大数运算。

/*B1011-A+B和C*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>
#include <stack>
using namespace std;

int main()
{
	int Num;
	long long  A, B, C;
	cin >> Num;
	for (int i = 0; i < Num; i++) 
	{
		cin >> A >> B >> C;
		cout << "Case #" << i + 1 << ":";
		if (A + B > C)
			cout << " true\n";
		else
			cout << " false\n";
	}
	
	return 0;
}

B1012.数字分类
有个点过不去,不知道为啥

#include <iostream>
#include <vector>

using namespace std;

vector<int> vec;

int main()
{
	int Num;
	int N;
	cin >> N;
	for (int i = 0; i < N; i++)
	{
		cin >> Num;
		vec.push_back(Num);
	}	

	int A1 = 0, A2 = 0, A3 = 0, A4Sum = 0, A5 = 0;
	int flag = 1;
	int A4Num = 0;
	int Now;
	for (int i = 0; i < vec.size(); i++)
	{	
		Now = vec[i];
		if (vec[i] % 10 == 0)
			A1 += vec[i];

		if (vec[i] % 5 == 1)
		{
			A2 = A2 + flag * vec[i];
			flag = -flag;
		}
		if (vec[i] % 5 == 2)
			A3++;
		if (vec[i] % 5 == 3) 
		{
			A4Sum += vec[i];
			A4Num++;
		}
		if (vec[i] % 5 == 4)
			if (vec[i] > A5)
				A5 = vec[i];
	}


	double A4;
	A4 = (double)A4Sum / (double)A4Num;

	if (A1 != 0) cout << A1 << " ";
	else cout << "N ";
	if (A2 != 0) cout << A2 << " ";
	else cout << "N ";
	if (A3 != 0) cout << A3 << " ";
	else cout << "N ";

	if (A4Sum != 0)
		printf("%.1lf ", A4);
	else
		cout << "N ";
	if (A5 != 0) cout << A5 ;
	else cout << "N";

	
	return 0;


}

B1013.数素数
写个IsPrime然后打印M个素数出来,最后按规格打印就可以了。

#include <iostream>
#include <vector>

using namespace std;

vector<int> Prime;

bool IsPrime(int Num)
{
	for (int i = 2; i *i <= Num; i++)
		if (Num % i == 0) return false;
	return true;
}

int main()
{
	int M, N,cnt = 0;
	cin >> M>> N;
	
	for (int a = 2; cnt<= N; a++)
	{
		if (IsPrime(a)) {
			Prime.push_back(a);
			cnt++;
		}
	}

	int flag = 0;
	for (; M <= N; M++)
	{	
		cout << Prime[M - 1];
		if (flag != 9) {
			if (M != N) {
				cout << " ";
				flag++;
			}
		}
		else
		{
			cout << "\n";
			flag = 0;
		}
	}

	return 0;
}

B1015.德才论
本题自己写的很乱,故参考了柳神题解。
注意用到了vector数组。其实就是一次性整n个vector放在一个数组中。 具体数据用struct打包起来。 写cmp的时候要注意题意,降序的意思是大的在前,升序才是小的在前。这里错了好几次。还有if里面的大于等于也要注意。

/*B1015*/
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Node 
{
	int ID;
	int de, cai;
};
typedef Node* Student;


vector<Student> V[4];//装有4个vector的数组


int cmp(Student a,Student b)
{
	if ((a->cai + a->de) != (b->de + b->cai))
		return (a->de + a->cai) > (b->de + b->cai);
	else if (a->de != b->de)
		return a->de > b->de;//降序,a比较大在前
	else
		return a->ID < b->ID;//升序,a比较大在后		
}


int main()
{
	int N, L, H;
	cin >> N >> L >> H;

	Student stu;
	int total = N;
	for (int i = 0; i < N; i++)
	{
		stu = new Node;
		cin >> stu->ID >> stu->de >> stu->cai;
		
		if (stu->de < L || stu->cai < L) //注意这里的原题意思
			total--;
		else if (stu->de >= H && stu->cai >= H) //注意是大于等于
			V[0].push_back(stu);
		else if (stu->de >= H && stu->cai < H)
			V[1].push_back(stu);
		else if (stu->de < H && stu->cai < H && stu->de >= stu->cai)
			V[2].push_back(stu);
		else
			V[3].push_back(stu);
	}
	cout << total<<"\n";

	for (int i = 0; i < 4; i++)
	{
		sort(V[i].begin(), V[i].end(), cmp);//按规则排序
		for (int j = 0; j < V[i].size(); j++)
			cout << V[i][j]->ID << " " << V[i][j]->de << " " << V[i][j]->cai << "\n";
	}

	return 0;
}

B1016.部分A+B
1.注意编码问题即可。也就是char 的6如果强制转换会转成54.故用 A - ‘0’ 做快捷又准确。
2.平方用pow()表示,它在 math.h库里面。

/*B1016 部分A+B*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;

int CaculateP(string A,char Da)
{
	int cnt = 0,num,sum = 0;
	for (int i = 0; i < A.length(); i++)
		if (A[i] == Da) cnt++;

	if (cnt != 0)
	{
		//num = (int)Da; //用这种方法会是num = 54 因为6的编码是54
		num = Da - '0';
		while (cnt != 0)
			sum += num * pow(10,--cnt);
		return sum;
	}
	else
		return 0;
}
int main()
{
	string A, B;
	char Da, Db;
	int Pa, Pb;

	cin >> A >> Da >> B >> Db;
	Pa = CaculateP(A, Da);
	Pb = CaculateP(B, Db);

	cout << Pa + Pb;

	return 0;
}

B1017.A除以B
大数运算,写手动除法。先拿左边数第一位除以被除数,然后除数输出,余数乘10加上下一位继续除,一直循环到末尾。

/*B1015*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;


int main()
{
	string A;
	int B;

	cin >> A >> B;
	if (A.length() < 17)
	{
		long long BeiChu;
		BeiChu = stoi(A);
		cout << BeiChu / B << " " << BeiChu%B;
	}
	else 
	{
		int tmp = 0;
		int len = A.length();
		int Shang = (A[0] - '0') / B;
		if ((Shang != 0 && len > 1) || len == 1)
			cout << Shang;

		tmp = (A[0] - '0') % B;
		for (int i = 1; i < len; i++)
		{	
			Shang = (tmp * 10 + (A[i] - '0')) / B;
			cout << Shang;
			tmp = (tmp * 10 + (A[i] - '0')) % B;
		}
		cout << " " << tmp;

	}
	return 0;
}

B1018.锤子剪刀布
比较麻烦的模拟题。注意三目运算符的使用方法。 以及最后输出的时候用一个str来极大的简化输出(来自柳神题解),自己写的话多写了好多行if。
但是挂了一个测试点,原因未知。

/*B1018*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;

int main()
{
	int N;
	cin >> N;

	int JW[3] = { 0 };
	int YW[3] = { 0 };//0代表B,1代表C,2代表J
	char Jia, Yi;
	int JWin = 0, YWin = 0;
	int Draw= 0;
	for (int i = 0; i < N; i++)
	{
		cin >> Jia >> Yi;
		if (Jia == 'C')
		{
			if (Yi == 'C') Draw++;
			if (Yi == 'J')
			{
				JWin++;
				JW[1]++;
			}
			if (Yi == 'B')
			{
				YWin++;
				YW[0]++;
			}
		}
		if (Jia == 'J')
		{
			if (Yi == 'J') Draw++;
			if (Yi == 'B')
			{
				JWin++;
				JW[2]++;
			}
			if (Yi == 'C')
			{
				YWin++;
				YW[1]++;
			}
		}
		if (Jia == 'B')
		{
			if (Yi == 'B') Draw++;
			if (Yi == 'C')
			{
				JWin++;
				JW[0]++;
			}
			if (Yi == 'J')
			{
				YWin++;
				JW[2]++;
			}
		}
	}

	cout << JWin << " " << Draw << " " << YWin << "\n";
	cout << YWin << " " << Draw << " " << JWin << "\n";

	int maxJ = JW[0] < JW[1] ? 1 : 0;
	maxJ = JW[maxJ] < JW[2] ? 2 : maxJ;
	int maxY = YW[0] < YW[1] ? 1 : 0;
	maxY = YW[maxY] < YW[2] ? 2 : maxY;

	string str = "BCJ";
	cout << str[maxJ] << " " << str[maxY];

	return 0;
}

B1019.数字黑洞 (考察str和Int的转化以及位数补全)
1.sort默认按升序排列,小的在前大的在后。如要改变需要自己写cmp。
2.sort返回void。
3.printf("%04d")代表不足4位补全0;
4.用str也可以补全。 str.insert( 补全的起始位置,要补多少个,‘要补的字符’),注意要补的字符是char类型,也就是必须是单引号。

/*B1019*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;

int cmp(char a, char b)
{
	return a > b ;//降序,a大时返回1,排序在前
}


int main()
{
	int N;
	cin >> N;
	if (N % 1111 == 0)
	{
		printf("%d - %d = 0000", N, N);
		return 0;
	}

	string str = to_string(N);
	str.insert(0, 4 - str.length(), '0');
	do {
		int Num1, Num2;
		
		sort(str.begin(), str.end(), cmp);//降序排序
		Num1 = stoi(str);
		sort(str.begin(), str.end());//升序排序
		Num2 = stoi(str);
		N = Num1 - Num2;
		printf("%04d - %04d = %04d\n", Num1, Num2, N);//printf的补全0
		str = to_string(N);
		str.insert(0, 4 - str.length(), '0');
	} while (str != "6174");

	return 0;
}

B1020.月饼
用一个结构体表示月饼的库存,总价和单价。要注意全都要是double类型。然后放到一个vec中,最后排序输出即可。
要注意vec(N)就已经申请好N个位置的空间了。如果是vec是空动态数组。
有个测试点段错误了,原因未知。

/*B1020*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;

struct MoonCake
{
	double stock;
	double price;
	double SinglePrice;
};

int cmp(MoonCake a, MoonCake b)
{
	return a.SinglePrice > b.SinglePrice; //单价高的排前面
}

int main()
{
	int N,D;
	cin >> N >> D;
	if (N == 0) return 0;
	vector<MoonCake> vec(N);
	for (int i = 0; i < N; i++)
	{
		double stock;
		cin >> stock;
		vec[i].stock = stock;
	}
	for (int i = 0; i < N; i++)
	{
		double price;
		cin >> price;
		vec[i].price = price;
	}
	for (int i = 0; i < N; i++)
		vec[i].SinglePrice = vec[i].price / vec[i].stock;

	sort(vec.begin(), vec.end(), cmp);

	int i = 0;
	double Result = 0.0;
	while (D > 0)
	{
		if (vec[i].stock <= D)
			Result += vec[i].price;
		else
			Result += vec[i].SinglePrice * D;	
		D = D - vec[i].stock;
		i++;
	}

	printf("%.2lf",Result);
	return 0;
}

B1021.个位数统计
又犯了同样的错误。char的1,如果用(int)强制转化,会转成ascii码的48,用char 的1 -‘0’才是数字1。

/*B1021*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>

using namespace std;

int main()
{
	string N;
	cin >> N;
	int Num[10] = {0};
	for (int i = 0; i < N.length(); i++)
		Num[N[i] - '0']++;

	for (int i = 0; i <= 9; i++)
	{
		if (Num[i] == 0) continue;
		else
			cout << i << ":" << Num[i]<<"\n";
	}

	return 0;
}

B1022.D进制的A+B (进制转换)
扩展2进制的转换写法,用原始数据除以D进制,根据每轮的余数推入堆栈,最后输出即可。
注意要排除被除数是0的情况。不然有个测试点挂了。

/*B1022*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>
#include <stack>

using namespace std;

int main()
{
	int D;
	long long int A, B,Sum;
	cin >> A >> B>> D;
	Sum = A + B;
	if (Sum == 0)
	{
		cout << 0;
		return 0;
	}

	int Yu,Shang = Sum;
	stack<int> S;
	
	while (Shang != 0)
	{
		Yu = Shang % D;
		S.push(Yu);
		Shang = Shang / D;
	}
	while(!S.empty())
	{
		cout<<S.top();
		S.pop();
	}
	return 0;
}

B1023.组个最小数
签到题

/*B1023*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>
#include <stack>

using namespace std;

int main()
{	
	int Num[10] = { 0 };
	vector<int> vec;
	
	for (int i = 0; i < 10; i++)
		cin >> Num[i];
	for (int i = 1; i < 10; i++)//输出第一位
	{
		if (Num[i] != 0)
		{
			cout << i;
			Num[i]--;
			break;
		}
	}
	for (int i = 0; i < 10; i++)
	{
		if (Num[i] != 0)
		{
			while (Num[i] != 0)
			{
				vec.push_back(i);
				Num[i]--;
			}
		}
	}
	if(vec.size()!= 0)
		sort(vec.begin(), vec.end());

	for (int i = 0; i < vec.size(); i++)
		cout << vec[i];
	return 0;
}

B1024.科学计数法
1.substr(起始位置,终止为止);
2.find(‘某个字母’),返回一个Int
3.要注意考虑指数没有底数长的情况,(可是还是挂了测试点)。

/*B1024*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>
#include <stack>

using namespace std;

int main()
{	
	string str;
	cin >> str;
	if (str[0] == '-') cout << "-";

	string Base, Index;
	int Epos = str.find('E');
	Base = str.substr(1, Epos-1);
	Index = str.substr(Epos + 1);

	int index = stoi(Index);
	if (index < 0)
	{
		cout << "0.";
		for (int i = 0; i < abs(index) - 1; i++)
			cout << "0";
		for (int i = 0; i < Base.length(); i++)
			if (Base[i] != '.')
				cout << Base[i];
	}
	else
	{	
		int len = Base.length();
		if (index+2 > len) {  //指数较长情况
			for (int i = 0; i < len ; i++)
				if (Base[i] != '.')
					cout << Base[i];
			for (int i = 0; i < index - 1; i++)
				cout << "0";
		}
		else//底数较长情况
		{
			for (int i = 0; i < index +2; i++)
				if (Base[i] != '.')
					cout << Base[i];
			cout << ".";
			Base = Base.substr(index + 2);//后半段
			cout << Base;
		}

	}
	return 0;
}

B1025.反转链表
建立三个数组分别储存data,next和地址重新排列的位置Relist。注意要引入Sum变量,因为并不是所有的节点都在链表中。
1.排除链表末尾的元素用取余来做。 sum-sum%K
2.遇到栈溢出。因为windows栈大小默认为1M,超过1M就会报错提示栈溢出:stack overflow,把数组放到全局变量里面就没事了
3.reverse反转函数。reverse(开始位置,结束位置)。本题中用begin(list)+K来找每个片段数组的起始位置。

/*B1025*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <math.h>
#include <stack>

using namespace std;


int Data[100006], Next[100006], Relist[100006];
//in function main(),array must within size 1mb,so I put them in global

int main()
{	
	int FirstAdress, N, K;
	cin >> FirstAdress >> N >> K;

	for (int i = 0; i < N; i++)
	{
		int tmp;
		cin >> tmp;
		cin >> Data[tmp] >> Next[tmp];
	}

	int sum = 0;
	while (FirstAdress != -1)//地址位置不等于负一
	{
		Relist[sum++] = FirstAdress;
		FirstAdress = Next[FirstAdress];
	}
	for (int i = 0; i < (sum - sum % K); i += K)//末尾多余部分(取余结果)不逆转
		reverse(begin(Relist)+i , begin(Relist)+i+K);//区间逆转

	for (int i = 0; i < sum - 1; i++)
		printf("%05d %d %05d\n", Relist[i], Data[Relist[i]], Relist[i + 1]);
	printf("%05d %d -1", Relist[sum - 1], Data[Relist[sum - 1]]);

	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值