6 C/C++输⼊输出(下)(未完续)

1. OJ(online judge)题⽬输⼊情况汇总

在竞赛的 OJ 题⽬中,⼀般关于输⼊场景总结为下⾯四类:

接下来,我们就结合题⽬,给⼤家分别介绍。

1.1 单组测试⽤例

练习1 B2009 计算 (a+b)/c 的值 - 洛谷 | 计算机科学教育新生态 128

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
	int a, b, c;
	//只处理一组数据
	cin >> a >> b >> c;
	cout << (a + b) / c << endl;
	return 0;
}

练习2:B2081 与 7 无关的数 - 洛谷 | 计算机科学教育新生态 128

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
	int n = 0;
	cin >> n;
	int i = 1;
	int sum = 0;
	while (i <= n)
	{
		if (i % 7 != 0 && i / 10 != 7 && i % 10 != 7)
		sum += i * i;
		i++;
	}
	cout << sum << endl;
	return 0;
}

1.2 多组测试⽤例

1.2.1 测试数据组数已知

练习1:多组输入a+b II 129

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
    int n = 0;
    int a = 0, b = 0;
    cin >> n;
    while (n--)
    {
        cin >> a >> b;
        cout << a + b << endl;
    }
    return 0;
}

练习2:B2064 斐波那契数列 - 洛谷 | 计算机科学教育新生态 129

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 40;
int arr[N] = {0,1,1};
int n,a;

int main()
{
	cin >> n;
	for(int i = 3; i <= 30; ++i)
	{
		arr[i] = arr[i-1] + arr[i-2];	
	}	
	while(n--)
	{
		cin >> a;
		cout << arr[a] << endl;
	}
	
    return 0;
}

练习3:B3769 [语言月赛202305] 制糊串 - 洛谷 | 计算机科学教育新生态 130

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
	string s,t;
	int q;
	int l1,l2,r1,r2;
	cin >> s >> t >> q;	
	while(q--)
	{
		cin >> l1 >> r1 >> l2 >> r2;
		//输入的下标是从1开始的,string substr(size_t pos = 0, size_t len = npos) const 
		string s1 = s.substr(l1-1,r1-l1+1);
		string t1 = t.substr(l2-1,r2-l2+1);
		if (s1 < t1) cout << "yifusuyi" << endl;
		else if (s1 > t1) cout << "erfusuer" << endl;
		else cout << "ovo" << endl;
	}
	
	return 0;
}

题⽬中说 "有 q 次询问",意思是程序要处理q组测试数据,(也就是对应 q 次循环),我们
要针对每次询问,给出⼀个结果。 其实就是之前的单组测试变成了 q 组测试,在之前的代码上套⼀层 while 循环即可。当 有 q 次询问的时候, while(q--) 是⾮常⽅便的⽅式。然后就按照单组输⼊的⽅式处理每 组输⼊的数据就好了。

1.2.2 测试数据组数未知

练习1:多组输入a+b 131

cpp 复制代码
#include <iostream>
using namespace std;
int a, b;
int main()
{
    while (cin >> a >> b)
    {
         cout << a + b << endl;
    }
    return 0;
}

cin >> a; 会返回⼀个流对象的引⽤,即 cin 本⾝。在 C++ 中,流对象 cin 可以被⽤ 作布尔值来检查流的状态。如果流的状态良好(即没有发⽣错误),流对象的布尔值为 true 。如果发⽣错误(如遇到输⼊结束符或类型不匹配),布尔值为 false 。 在 while (cin >> a >> b) 语句中,循环的条件部分检查 cin 流的状态。如果流成 功读取到2个值, cin >> a >> b 返回的流对象 cin 将被转换为 true ,循环将继 续。如果读取失败(例如遇到输⼊结束符或⽆法读取到2个值), cin >> a >> b 返回的 流对象 cin 将被转换为 false ,循环将停⽌

练习2:数字三角形 131

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
    int n;
    while(cin >> n)
    {
        //打印行
        for(int i = 1; i <=n; ++i)
        {
            //打印每一行的元素
            for(int j = 1; j <= i; ++j)
            {
                cout << j << " ";
            }
            cout << endl;
        }
    }
    return 0;
}

练习3:定位查找 132

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 25;
int arr[N];
int n,m;

int main()
{
	while(cin >> n)
	{
		for(int i = 0; i < n; ++i)
		{
			cin >> arr[i];
		}
		cin >> m;
		int i = 0;
		for(i; i < n; ++i)
		{
			if (m == arr[i]) {
				cout << i << endl;
				break;
			}
		}
        //最好在题目中复制
		if (i == n) cout << "No" << endl;
	}
    return 0;
}

1.2.3 特殊值结束测试数据

练习1:字符统计 133

cpp 复制代码
#include <iostream>
using namespace std;

int l,d,o; 

int main()
{
	int ch = 0;
	while((ch = getchar()) != '?') 
	{
		if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' ) l++;
		else if (ch >= '0' && ch <= '9') d++;
		else o++;
	}
	
	cout << "Letters=" << l << endl;
    cout << "Digits=" << d << endl;
    cout << "Others=" << o << endl;
    
	return 0;
}

//islower isupper isdigit
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int l,d,o;

int main()
{
	int ch = 0;
	while((ch = getchar()) != '?') 
	{
		if (islower(ch) || isupper(ch)) l++;
		else if (isdigit(ch)) d++;
		else o++;
	}
	cout << "Letters=" << l << endl;
    cout << "Digits=" << d << endl;
    cout << "Others=" << o << endl;
    
	return 0;
}

//isalpha 
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int l,d,o;

int main()
{
	int ch = 0;
	while((ch = getchar()) != '?') 
	{
		if (isalpha(ch)) l++;
		else if (isdigit(ch)) d++;
		else o++;
	}
	cout << "Letters=" << l << endl;
    cout << "Digits=" << d << endl;
    cout << "Others=" << o << endl;
    
	return 0;
}

//getline
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int l,d,o;

int main()
{
	string s;
	getline(cin, s);
	s.pop_back();//删掉?最后一个字符 

	for(auto ch : s)
	{
		if (isalpha(ch)) l++;
		else if (isdigit(ch)) d++;
		else o++;
	}
	
	cout << "Letters=" << l << endl;
    cout << "Digits=" << d << endl;
    cout << "Others=" << o << endl;
    
	return 0;
}

练习2:多组数据a+b III 134

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
	int a = 0, b = 0;
	//逗号表达式特点
	//1.从左向右依次计算
	//2.整个表达式结果是最后一个表达式的结果 
	while (cin >> a >> b, a || b)
	{
		cout << a + b << endl;
	}
 	return 0;
}

2. 输⼊时特殊技巧

2.1 技巧1:含空格字符串的特殊处理⽅式

根据我们现在掌握的知识,含空格的字符串,如要读取有 fgets 、 scanf 、 getchar 、 getline 四种⽅式解决,但是有时候,根据题⽬的情况,不⼀定⾮要完整的 读取这个带空格的字符串, ⽽是将字符串中空格隔开的每⼀个字符串,当做⼀个单词处理更⽅便,也避免了读取带空格字符串的各种问题。

练习:B2109 统计数字字符个数 - 洛谷 | 计算机科学教育新生态 135

解法1:读取整个带空格的字符串分析

cpp 复制代码
//getline
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int main() {
	string s;
	getline(cin, s);
	int c = 0;
	for(auto ch : s)
	{
		if (isdigit(ch)) c++;
	}
	cout << c << endl;
	return 0;
}

解法2:按照多个单词分析

cpp 复制代码
//cin
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

int main() {
	string s;
	int c = 0;
	while(cin >> s)
	{
		for(auto ch : s)
		{
			if (isdigit(ch)) c++;
		}
	}
	
	cout << c << endl;
	
	return 0;
}

2.2 技巧2:数字的特殊处理⽅式

当我们程序运⾏的时候,在控制台输⼊ 123 的时候,这时的 123 是三个字符, 123 是⼀个字符序列,程序会根据代码中的数据类型,可能将 123 解析成整型,也可能将 123 解析成字符串。 ⽐如:

cpp 复制代码
int num = 0;
cin >> num;//输⼊123, 就被解析成整数
string s;
cin >> s; //输⼊123, 就被解析成字符串

这⾥的解析的⽅式,主要是依赖编译器对变量类型的识别,根据类型再将读取字符串数据转化成对应类型的数据。 我们在写代码的时候,应该根据实际的情况,来决定如何处理输⼊的内容。

练习:小乐乐改数字_牛客题霸_牛客网 136

解法1:当做整数读取

cpp 复制代码
//double pow (double base, double exponent);

#include <iostream>
#include <cmath>
using namespace std;

int main() {
	int n;
	cin >> n;
	int ret = 0;
	int i = 0;
	while(n)
	{
		if (n % 10 % 2)
			ret += pow(10,i);
		n /= 10;
		++i;
	}
	cout << ret << endl;
	return 0;
}

解法2:当做字符串处理

cpp 复制代码
#include <iostream>
#include <string>
#include <cmath>
using namespace std;

int main() {
	string s;
	cin >> s;

	for(int i = 0; i < s.size(); ++i)
	{
		//'0' = 48
		//'1' = 49
		if (s[i] % 2)
			s[i] = '1';
		else 
			s[i] = '0';
	}
	cout << stoi(s) << endl;
	
	return 0;
}

3. scanf/printf 和 cin/cout的对⽐

scanf 和 printf 是 C 语⾔中的标准输⼊输出函数,⽽ cin 和 cout 是 C++ 语⾔中的标准输⼊输出流对象。它们各⾃有优缺点,整体上来说 cin 和 cout 会更加⽅便,但有时候我们也不得不 使⽤ scanf 和 printf 。

3.1 格式控制差异

·scanf 和 printf 不能⾃动识别输⼊数据的类型,需要⼿动指定格式字符串,容易出现格式错
误。开发者需要确保格式字符串与变量类型匹配,否则会导致未定义⾏为。
·cin 和 cout 会根据变量类型⾃动处理输⼊输出,避免格式化错误。相对 scanf 和 printf
⽽且,C++的 cin 和 cout 更加易⽤。
·scanf 和 printf :格式化输出更精确直观,特别适合复杂格式的输⼊输出,⽐如:在要求指
定格式输出的时候, printf 函数就⽐ cout 更加⽅便和灵活。

cpp 复制代码
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
	float a = 3.50;
	double d = 16.50;
 
	cout << "cout: " <<a << " "<< d <<endl;
	printf("printf: %f %lf\n", a, d);
	
	return 0;
}
//cout: 3.5 16.5
//printf: 3.500000 16.500000
  1. cout 默认不会输出六位⼩数,⾃动忽略⼩数点后多余的 0 , printf 函数打印浮点数的时候,⼩数点默认打印6位。
  2. cout 在输出的时候不需要指定格式, printf 则需要明确的格式。

3.2 性能差异

3.2.1 案例演⽰

结论: scanf 和 printf 通常⽐ cin 和 cout 快。
原因: cin 和 cout 由于要考虑兼容C语⾔的输⼊和输出,封装实现的更加复杂,通常⽐ scanf 和 printf 稍慢,但这种差异在⼤多数应⽤场景中可以忽略不计。 但是在竞赛的题⽬中,尤其是当输⼊、输出数据量较⼤时,使⽤ cin 和 cout 完成输⼊输出,经常 会出现 Time Limit Exceeded 的情况。⽽ scanf 和 printf 就不存在类似的问题。下⾯给⼤ 家准备了两个案例。

案例1:数字游戏

相关推荐
半盏茶香20 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦27 分钟前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
DARLING Zero two♡1 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
字节高级特工1 小时前
【优选算法】5----有效三角形个数
c++·算法
荣--2 小时前
HiJobQueue:一个简单的线程安全任务队列
c++·编码
肖田变强不变秃10 小时前
C++实现矩阵Matrix类 实现基本运算
开发语言·c++·matlab·矩阵·有限元·ansys
雪靡14 小时前
正确获得Windows版本的姿势
c++·windows
可涵不会debug14 小时前
【C++】在线五子棋对战项目网页版
linux·服务器·网络·c++·git