天方夜谭之——c算法题库2
引言
在本文列举了常用 c算法,程包括程序设计思想、代码。
99 自动售货系统
描述
1 总体说明
考生需要模拟实现一个简单的自动售货系统,实现投币、购买商品、退币、查询库存商品及存钱盒信息的功能。
系统初始化时自动售货机中商品为6种商品,商品的单价参见1.1规格说明,存钱盒内放置1元、2元、5元、10元钱币,商品数量和钱币张数通过初始化命令设置,参见2.1 系统初始化。
1.1规格说明
- 商品:每种商品包含商品名称、单价、数量三种属性,其中商品名不重复。考生不能修改商品名称和单价,初始化命令设置商品数量。这些信息在考试框架中进行定义,考生在实现功能代码时可直接使用。
商品 名称 单价 数量
A1 2 X
A2 3 X
A3 4 X
A4 5 X
A5 8 X
A6 6 X - 存钱盒信息:钱币面额、张数两种属性。初始化命令设置各种面额钱币张数。这些信息在考试框架中进行定义,考生在实现功能代码时可直接使用。
钱币面额 张数
10元 X
5元 X
2元 X
1元 X - 退币原则 :
- 根据系统存钱盒内钱币的 信息 ,按钱币总张数最少的原则进行退币。
- 如果因零钱不足导致不能退币,则尽最大可能退币,以减少用户损失。
例如:假设存钱盒内只有4张2元,无其它面额钱币。如果需要退币7元,系统因零钱不足无法退币,则继续尝试退币6元,最终系统成功退币3张2元,用户损失1元钱币。
- 投币操作说明:每次投币成功,投入的钱币面额累加到投币余额;同时,本次投入的钱币放入存钱盒中,存钱盒相应面额钱币增加。
- 投币余额:指当前自动售货机中用户剩余的可购买商品的钱币总额;例如:投入2元面额的钱币,投币余额增加2元;购买一件价格2元的商品,投币余额减少2元;
- 退币操作说明:退币操作需要遵守 退币原则 ;退币成功后,投币余额清零,同时扣除存钱盒相应的金额。
- 购买商品操作说明:一次仅允许购买一件商品;购买商品成功后,自动售货机中对应商品数量减1,投币余额扣除本次购买商品的价格。
2 操作说明
命令字与第一个参数间使用一个空格分隔,多条命令采用分号隔开。考试系统会对输入命令格式进行处理,考生不需要关注输入命令格式的合法性,只需要实现命令处理函数。
2.1 系统初始化
命令格式:
r A1 数量 -A2 数量 -A3 数量 -A4 数量 -A5 数量 -A6 数量 1 元张数 -2 元张数 -5 元张数 -10 元张数
参数名称 参数说明 类型 取值范围
A1数量 商品A1数量 整数 [0,30]
A2数量 商品A2数量 整数 [0,30]
A3数量 商品A3数量 整数 [0,30]
A4数量 商品A4数量 整数 [0,30]
A5数量 商品A5数量 整数 [0,30]
A6数量 商品A6数量 整数 [0,30]
1元张数 面额1元钱币张数 整数 [0,30]
2元张数 面额2元钱币张数 整数 [0,30]
5元张数 面额5元钱币张数 整数 [0,30]
10元张数 面额10元钱币张数 整数 [0,30]
商品和各种面额钱币取值范围只是作为初始化命令的限制,其它场景下不限制取值范围;考试框架已经实现取值范围的检查,考生不需要关注。
功能说明:设置自动售货机中商品数量和存钱盒各种面额的钱币张数;
约束说明:系统在任意阶段均可执行r初始化系统;考生不需要关注参数的合法性,不需要关注增加或缺少参数的场景;
输出说明:输出操作成功提示(执行完r命令后系统会自动输出操作结果,考生不需要再次调用输出函数),例:
命令 输出 含义
r 6-5-4-3-2-1 4-3-2-1; S001:Initialization is successful 初始化成功
2.2 投币
命令格式:p 钱币面额
功能说明:
(1) 如果投入非1元、2元、5元、10元的钱币面额(钱币面额不考虑负数、字符等非正整数的情况),输出“E002:Denomination error”;
(2) 如果存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额,输出“E003:Change is not enough, pay fail”,但投入1元和2元面额钱币不受此限制。
(3) 如果自动售货机中商品全部销售完毕,投币失败。输出“E005:All the goods sold out”;
(4) 如果投币成功,输出“S002:Pay success,balance=X”;
约束说明:
(1) 系统在任意阶段都可以投币;
(2) 一次投币只能投一张钱币;
(3) 同等条件下,错误码的优先级:E002 > E003 > E005;
输出说明:如果投币成功,输出“S002:Pay success,balance=X”。
例:
命令 输出
p 10; S002:Pay success,balance=10
2.3 购买商品
命令格式:b 商品名称
功能说明:
(1) 如果购买的商品不在商品列表中,输出“E006:Goods does not exist”;
(2) 如果所购买的商品的数量为0,输出“E007:The goods sold out”;
(3) 如果投币余额小于待购买商品价格,输出“E008:Lack of balance”;
(4) 如果购买成功,输出“S003:Buy success,balance=X”;
约束说明:
(1) 一次购买操作仅能购买一件商品,可以多次购买;
(2) 同等条件下,错误码的优先级:E006 > E007 > E008;
输出说明:
如果购买成功,输出“S003:Buy success,balance=X”。
例:
命令 输出
b A1; S003:Buy success,balance=8
2.4 退币
命令格式:c
功能说明:
(1) 如果投币余额等于0的情况下,输出“E009:Work failure”;
(2) 如果投币余额大于0的情况下,按照 退币原则 进行“找零”,输出退币信息;
约束说明:
(1) 系统在任意阶段都可以退币;
(2) 退币方式必须按照 退币原则 进行退币;
输出说明:如果退币成功,按照 退币原则 输出退币信息。
例,退5元钱币:
命令 输出
c; 1 yuan coin number=0
2 yuan coin number=0
5 yuan coin number=1
10 yuan coin number=0
2.5 查询
命令格式:q 查询类别
功能说明:
(1) 查询自动售货机中商品信息,包含商品名称、单价、数量。 根据商品数量从大到小进行排序;商品数量相同时,按照商品名称的先后顺序进行排序 。
例如:A1的商品名称先于A2的商品名称,A2的商品名称先于A3的商品名称。
(2) 查询存钱盒信息,包含各种面额钱币的张数;
(3) 查询类别如下表所示:
查询类别 查询内容
0 查询商品信息
1 查询存钱盒信息
如果“查询类别”参数错误,输出“E010:Parameter error”。“查询类别”参数错误时,不进行下面的处理;
输出说明:
“查询类别”为0时,输出自动售货机中所有商品信息(商品名称单价数量)例:
命令 输出
q 0; A1 2 6
A2 3 5
A3 4 4
A4 5 3
A5 8 2
A6 6 0
“查询类别”为1时,输出存钱盒信息(各种面额钱币的张数),格式固定。例:
命令 输出
q 1; 1 yuan coin number=4
2 yuan coin number=3
5 yuan coin number=2
10 yuan coin number=1
输入描述:
依照说明中的命令码格式输入命令。
输出描述:
输出执行结果
示例1
输入:
r 22-18-21-21-7-20 3-23-10-6;c;q0;p 1;b A6;c;b A5;b A1;c;q1;p 5;
r 28-12-11-1-16-10 19-30-8-11;b A1;p 1;
输出:
S001:Initialization is successful
E009:Work failure
E010:Parameter error
S002:Pay success,balance=1
E008:Lack of balance
1 yuan coin number=1
2 yuan coin number=0
5 yuan coin number=0
10 yuan coin number=0
E008:Lack of balance
E008:Lack of balance
E009:Work failure
E010:Parameter error
S002:Pay success,balance=5
S001:Initialization is successful
E008:Lack of balance
S002:Pay success,balance=1
代码c++
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
class Goods
{
private:
string name;
int price;
int num;
public:
Goods(){
name = "NONE";
price = 0;
num = 0;
}
Goods(string str, int i, int j){
name = str;
price = i;
num = j;
}
void Init(int j){
num = j;
}
string& NAME(){return name;}
int& PRICE(){return price;}
int& NUM(){return num;}
void addGoods(int i = 1){
num += i;
}
void reduceGoods(int i = 1){
num -= i;
}
};
class SavingBox
{
private:
unordered_map<int, int> coins;
public:
SavingBox(){
coins[1] = 0;
coins[2] = 0;
coins[5] = 0;
coins[10] = 0;
}
SavingBox(unordered_map<int, int>& index){
for(auto iter = index.begin(); iter != index.end(); iter++){
coins[iter->first] = iter->second;
}
}
unordered_map<int, int>& COINS(){return coins;};
void Init(unordered_map<int, int>& index){
for(auto iter = index.begin(); iter != index.end(); iter++){
coins[iter->first] = iter->second;
}
}
void addCoin(int i, int j=1){
coins[i] += j;
}
void reduceCoin(int i, int j=1){
coins[i] -= j;
}
int getCoinNum(int i){
if(coins.count(i)){
return coins[i];
}else{
throw("输入错误");
}
}
};
class VendingSystem
{
private:
vector<string> names = {"A1", "A2", "A3", "A4", "A5", "A6"};
vector<int> prices = {2,3,4,5,8,6};
vector<Goods> shops;
vector<int> coins = {1,2,5,10};
SavingBox box;
int balance; // 投币余额
public:
VendingSystem(){
for(int i =0; i < 6; i++){
shops.push_back(Goods(names[i], prices[i], 0));
}
unordered_map<int, int> index;
for(int k = 0; k < int(coins.size()); k++){
index[coins[k]] = 0;
}
box = SavingBox(index);
balance = 0;
}
void Run(string str){
if(str[0] == 'r'){
Init(str);
}else if(str[0] == 'p'){
Pay(str);
}else if(str[0] == 'b'){
Buy(str);
}else if(str[0] == 'c'){
Change();
}else if(str[0] == 'q'){
Query(str);
}else{
throw("输入错误");
}
}
void Init(string str){
balance = 0;
// 22-18-21-21-7-20 3-23-10-6
str = str.substr(2, str.size()-2);
string initGoodCmd = str.substr(0, str.find(' '));
string initBoxCmd = str.substr(str.find(' ')+1, str.size()-str.find(' ')-1);
vector<int> nums;
int i = 0, j= 0;
while(j < int(initGoodCmd.size())){
if(initGoodCmd[j] == '-'){
nums.push_back(atoi(initGoodCmd.substr(i, j-i).c_str()));
i = j+1;
}
j++;
}
nums.push_back(atoi(initGoodCmd.substr(i, j-i).c_str()));
for(int k = 0; k < 6; k++){
shops[k].Init(nums[k]);
}
nums.clear();
i = 0, j = 0;
while(j < int(initBoxCmd.size())){
if(initBoxCmd[j] == '-'){
nums.push_back(atoi(initBoxCmd.substr(i, j-i).c_str()));
i = j+1;
}
j++;
}
nums.push_back(atoi(initBoxCmd.substr(i, j-i).c_str()));
unordered_map<int, int> index;
for(int k = 0; k < int(coins.size()); k++){
index[coins[k]] = nums[k];
}
box.Init(index);
cout << "S001:Initialization is successful" << endl;
}
void Pay(string str){
//获取面额
int money = atoi(str.substr(2, str.size()-2).c_str());
if(!count(coins.begin(), coins.end(), money)){
cout << "E002:Denomination error" << endl;
return;
}
if(money == 5 || money == 10){
if((box.getCoinNum(1)+box.getCoinNum(2)*2) < money){
cout << "E003:Change is not enough, pay fail" << endl;
return;
}
}
//查询剩余商品数量
bool flag = true;
for(auto shop: shops){
if(shop.NUM() > 0){
flag = false;
break;
}
}
if(flag){
cout << "E005:All the goods sold out" << endl;
return;
}
// 投币成功
balance += money;
box.addCoin(money);
cout << "S002:Pay success,balance=" << balance << endl;
}
void Buy(string str){
string name = str.substr(2, str.size()-1);
if(!count(names.begin(), names.end(), name)){
cout << "E006:Goods does not exist" << endl;
return;
}
Goods& shop = shops[distance(names.begin(),find(names.begin(), names.end(), name))];
if(shop.NUM() == 0){
cout << "E007:The goods sold out" << endl;
return;
}
if(shop.PRICE() > balance){
cout << "E008:Lack of balance" << endl;
return;
}
//购买成功
shop.reduceGoods();
balance -= shop.PRICE();
cout << "S003:Buy success,balance=" << balance << endl;
}
void Change(){
if(balance == 0){
cout << "E009:Work failure" << endl;
return;
}
vector<int> info(coins.size());
for(int i = coins.size()-1; i >= 0; i--){
int coin = coins[i];
while(balance >= coin && box.getCoinNum(coin) > 0){
balance -= coin;
box.reduceCoin(coin);
info[i]++;
}
}
for(int i = 0; i < int(info.size()); i++){
cout << coins[i] << " yuan coin number=" << info[i] << endl;
}
}
void Query(string str){
if(str == "q 0"){
// 根据商品数量从大到小排序
vector<Goods> shops_ = shops;
sort(shops_.begin(), shops_.end(), cmp);
for(auto shop: shops_){
cout << shop.NAME() << " " << shop.PRICE() << " " << shop.NUM() << endl;
}
return;
}
if(str == "q 1"){
for(int coin: coins){
cout << coin << "yuan coin number=" << box.getCoinNum(coin) << endl;
}
return;
}
cout << "E010:Parameter error" << endl;
}
static bool cmp(Goods g1, Goods g2){
return g2.NUM() < g1.NUM();
}
};
int main()
{
string str;
vector<string> cmds;
VendingSystem sys;
while(getline(cin, str)){
int i = 0, j = 0;
cmds.clear();
while(j < int(str.size())){
if(str[j] == ';'){
cmds.push_back(str.substr(i, j-i));
i = j + 1;
}
j++;
}
for(unsigned int i = 0; i < cmds.size(); i++){
//cout << cmds[i] << endl;
sys.Run(cmds[i]);
}
}
}
100 自守数
描述
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n(包括n)以内的自守数的个数
本题有多组输入数据
数据范围:
输入描述:
int型整数
输出描述:
n以内自守数的数量。
示例1
输入:
5
2000
输出:
3
8
说明:
对于样例一,有0,1,5,这三个自守数
示例2
输入:
1
输出:
2
说明:
有0, 1这两个自守数
代码
#include <stdio.h>
#include <string.h>
#define SIZE 10000
int arr[100]; //自守数数组
void getnum(int size);
int checknum(int num);
int main(void)
{
getnum(SIZE);
int num;
while(scanf("%d",&num)!=EOF){
printf("%d\n",checknum(num));
}
return 0;
}
void getnum(int size)
{
int i,j,tmp;
arr[0] = 1,arr[1] = 5,arr[2] = 6; //前四个自守数易得
for(i=7,j=3;i<=SIZE;i++){
if(i<10) tmp = 10;
else if(i<100) tmp = 100;
else if(i<1000) tmp = 1000;
else if(i<10000) tmp = 10000;
else tmp = 100000;
if((i*i - i) % tmp == 0){
arr[j++] = i; //记录自守数
}
}
}
int checknum(int num)
{
int i = 0; //因为要判断0,所以自守数数组内没有0,输出要+1多一个
while(num >= arr[i] && arr[i]!=0) i++;
return i+1;
}
101 等差数列
描述
等差数列 2,5,8,11,14。。。。
(从 2 开始的 3 为公差的等差数列)
输出求等差数列前n项和
本题有多组输入
数据范围:
输入描述:
输入一个正整数n。
输出描述:
输出一个相加后的整数。
示例1
输入:
2
输出:
7
说明:
2+5=7
示例2
输入:
275
输出:
113575
说明:
2+5+…+821+824=113575
代码
#include<stdio.h>
int main(int argc, char const *argv[])
{
int in_num=0;
int a1=2, d=3;
int an=0, out_sum=0;
while (scanf("%d", &in_num) != EOF)
{
out_sum=0;
an=0;
an = a1 + (in_num - 1)*d;
out_sum = (a1 + an)* in_num/2;
printf("%d\n", out_sum);
}
return 0;
}
102 输入整型数组和排序标识,对其元素按照升序或降序进行排序
描述
输入整型数组和排序标识,对其元素按照升序或降序进行排序
数据范围: ,元素大小满足
输入描述:
第一行输入数组元素个数
第二行输入待排序的数组,每个数用空格隔开
第三行输入一个整数0或1。0代表升序排序,1代表降序排序
输出描述:
输出排好序的数字
示例1
输入:
8
1 2 4 9 3 55 64 25
0
输出:
1 2 3 4 9 25 55 64
示例2
输入:
5
1 2 3 4 5
1
输出:
5 4 3 2 1
代码
#include<stdio.h>
int main(int argc, char const *argv[])
{
int num = 0, sflag = 0, ntmp = 0, stmp = 0;
while (scanf("%d", &num) != EOF)
{
int arrays[num];
for (int i = 0; i < num; i++)
{
ntmp = 0;
scanf("%d", &ntmp);
arrays[i] = ntmp;
}
scanf("%d", &sflag);
//冒泡排序
for (int i = 0; i < num; i++)
{
for (int j = i+1; j < num; j++)
{
if (sflag == 1)
{
//降序
if (arrays[i] < arrays[j])
{
stmp = 0;
stmp = arrays[i];
arrays[i] = arrays[j];
arrays[j] = stmp;
}
}
else
{
//升序
if (arrays[i] > arrays[j])
{
stmp = 0;
stmp = arrays[i];
arrays[i] = arrays[j];
arrays[j] = stmp;
}
}
}
}
//打印数组
for (int i = 0; i < num; i++)
{
printf("%d ", arrays[i]);
}
printf("\n");
}
return 0;
}
103 字符统计
描述
输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。
本题含有多组样例输入
数据范围:字符串长度满足
输入描述:
一个只包含小写英文字母和数字的字符串。
输出描述:
一个字符串,为不同字母出现次数的降序表示。若出现次数相同,则按ASCII码的升序输出。
示例1
输入:
aaddccdc
1b1bbbbbbbbb
输出:
cda
b1
说明:
第一个样例里,c和d出现3次,a出现2次,但c的ASCII码比d小,所以先输出c,再输出d,最后输出a.
思想
代码
int main(void) {
char s[1000] = "";
while(gets(s)) {
int result[131] = {0};
char s1[1000] = "";
int maxIndex = 0;
int max = 0;
int i = 0;
int count = 0;
int j =0 ;
for(i = 0; i < strlen(s); i++) {
result[s[i]]++;
}
for(i = 0; i < 131; i++) {
if(result[i] > 0)
count++;
}
while(j < count) {
max = 0;
maxIndex = 0;
for(i = 0; i < 131; i++) {
if(max < result[i]) {
max = result[i];
maxIndex = i;
}
}
result[maxIndex] = 0;
s1[j] = (char)maxIndex;
j++;
}
printf("%s\n", s1);
}
}
104 Redraiment的走法(不懂题意)
描述
Redraiment是走梅花桩的高手。Redraiment可以选择任意一个起点,从前到后,但只能从低处往高处的桩子走。他希望走的步数最多,你能替Redraiment研究他最多走的步数吗?
数据范围:每组数据长度满足 , 数据大小满足
本题含有多组样例输入
输入描述:
输入多组数据,1组有2行,第1行先输入数组的个数,第2行再输入梅花桩的高度
输出描述:
一组输出一个结果
示例1
输入:
6
2 5 1 5 4 5
3
3 2 1
输出:
3
1
说明:
6个点的高度各为 2 5 1 5 4 5
如从第1格开始走,最多为3步, 2 4 5 ,下标分别是 1 5 6
从第2格开始走,最多只有1步,5
而从第3格开始走最多有3步,1 4 5, 下标分别是 3 5 6
从第5格开始走最多有2步,4 5, 下标分别是 5 6
所以这个结果是3。
代码
#include <stdlib.h>
#include <stdio.h>
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
int arr[300] = {0}, dp[300] = {0};
for(int i=0; i<n; i++)
{
scanf("%d", &arr[i]);
}
dp[0] = 1;
int maxans = 1;
for(int i=1; i<n; i++)
{
int maxval = 0;
for(int j=0; j<i; j++)
{
if(arr[i] > arr[j])
maxval = (maxval > dp[j]) ? maxval : dp[j];
}
dp[i] = maxval + 1;
maxans = (maxans > dp[i]) ? maxans : dp[i];
}
printf("%d\n", maxans);
}
return 0;
}
105 记负均正II
描述
输入 n 个整型数,统计其中的负数个数并求所有非负数的平均值,结果保留一位小数,如果没有非负数,则平均值为0
本题有多组输入数据,输入到文件末尾。
数据范围: ,其中每个数都满足
输入描述:
输入任意个整数,每行输入一个。
输出描述:
输出负数个数以及所有非负数的平均值
示例1
输入:
-13
-4
-7
输出:
3
0.0
示例2
输入:
-12
1
2
输出:
1
1.5
代码
#include <stdio.h>
#include <string.h>
int main()
{
int num, cnt1=0, cnt2=0, sum=0;
while(scanf("%d",&num) != EOF)
{
if(num < 0)
{
cnt1++;
}
else
{
sum += num;
cnt2++;
}
}
float result =(cnt2>0)?((float) sum / cnt2):0;
printf("%d\n%0.1f\n",cnt1,result);
return 0;
}
106 字符逆序
描述
将一个字符串str的内容颠倒过来,并输出。
数据范围:
输入描述:
输入一个字符串,可以有空格
输出描述:
输出逆序的字符串
示例1
输入:
I am a student
输出:
tneduts a ma I
示例2
输入:
nowcoder
输出:
redocwon
代码
#include <stdio.h>
int main(){
char str[100];
char i=0;
while((str[i]=getchar())!='\n') i++;
i--; //去掉\n
while(i>=0) printf("%c",str[i--]);
return 0;
}
107 求解立方根
描述
计算一个浮点数的立方根,不使用库函数。
保留一位小数。
数据范围:
输入描述:
待求解参数,为double类型(一个实数)
输出描述:
输入参数的立方根。保留一位小数。
示例1
输入:
216
输出:
6.0
示例2
输入:
2.7
输出:
1.4
思想
求立方根,将思路改变为循环+0.01并求三次方,判断是否接近输入参数n
注意区分正负数
代码
#include <stdio.h>
#include <math.h>
int main()
{
double n,m;
double i=0.1;
scanf("%lf",&n);
if(n>0)
{
while(i*i*i<n)
{
i=i+0.01;
}
printf("%.1lf",i);
}
else
{
m=-n;
while(i*i*i<m)
{
i=i+0.01;
}
printf("%.1lf",-i);
}
}
108 求最小公倍数
描述
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
数据范围:
输入描述:
输入两个正整数A和B。
输出描述:
输出A和B的最小公倍数。
示例1
输入:
5 7
输出:
35
示例2
输入:
2 4
输出:
4
不同思想
求最小公倍数 if(i%m0 && i%n0)
代码
#include<stdio.h>
int main()
{
int a , b , temp , i , sum;
scanf("%d %d",&a,&b);
if(a<b)
{
temp=b;
b=a;
a=temp;
}
sum=a*b;
i=a%b;
while(i!=0)
{
a=b;
b=i;
i=a%b;
}
printf("%d",sum/b);
感谢阅读,祝君成功!
-by aiziyou