Skip to content

字符串图形

Q1 三角形

markdown
输入一个整数n(0<n<26),表示字母三角形的层数。
输出三角形字母
案例,n=2;
 A
BBB
c++
#include<iostream>
#include <string>
using namespace std;
int main(){
    int n;
    cin>>n;
    for(int i =1; i<=n;++i){
        string s = string (n-i,' ');
        string ch = string (2 * i - 1,'A'+ i - 1);
        cout<<s  + ch <<endl;
    }
}
输入一个整数n(0<n<26)或者字母。
输出三角形
案例,s=A;
 A
ABA
c++
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int main() {
	char c; 
	cin >> c;
	if(c>='A'&&c<='Z') {
		for (int i = 1; i <= c - 'A' + 1; i++) {
			for (int j = 1; j <= c - 'A' + 1 - i; j++) {
				cout << " ";//差几个打几个空格
			}
			for (int j = 1; j <= i; j++) {
				cout << (char)('A' + j - 1);
			}
			for (int j = i - 1; j >= 1; j--) {
				cout << (char)('A' + j - 1);
			}
			cout << endl;
		}
	}
	else {
		for (int i = 1; i <= c - '1' + 1; i++) {
			for (int j = 1; j <= c - '1' + 1 - i; j++) {
				cout << " ";
			}
			for (int j = 1; j <= i; j++) {
				cout << (char)('1' + j - 1);
			}
			for (int j = i - 1; j >= 1; j--) {
				cout << (char)('1' + j - 1);
			}
			cout << endl;
		}
	}
	return 0;
}

Q2 建房子包围宝藏

假设地图是一个n行m列的方格地图,地图每个格子*代表一个宝藏。比如2行2列的地图如下

markdown
**
**

建造的房子是:

+-+-+
|*|*|
+-+-+
|*|*|
+-+-+
markdown
现在蒜头君告诉你地图的行列数,帮他画出房子的设计图。
输入格式
一行两个整数n,m(0<n,m<=50),分别表示地图行数和列数。
输出格式
按照题目中要求的格式输出地图
c++
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int main() {
	int n,m ;
	
	cin >> n>> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cout << "+-";
		}

		cout << "+"<<endl;
		for (int j = 1; j <= m; j++) {
			cout << "|*";
		}
		cout << "|" << endl;
	}
		for (int j = 1; j <=m; j++) {
			cout << "+-";
		}
		cout << "+" << endl;
	return 0;
}

日期

1闰年

  • 闰年是一类比较特殊的年份,闺年比平年(非润年)在2月份多一天。关于闰年的判断,很多同学还不是很清楚,下面是闺年的详细定义:
  • 1.年份非整百且能被4整除的为年。 (如2004年就是年2005年不是年)
  • 2年份能被400整除的是年。 (如2000年是年,1900年不是年)需要特别注意,能被100整除的年份,必须要被400整除才是闺年。
c++
int is_leap_year(int year){
	if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ){
		return 1;
	}
	return 0;
}

2星期

例子1:星期几

  • 已知:1年1月1日是星期一
  • 输入格式 输入三个正整数,分别表示年、月、日。保证输入年份合法。
  • 输出格式 输出星期几。用 Monday 、Tuesday 、Wednesday 、Thursday,Friday,Sunday 表示星期几。

  • 记住很久以前的某一天是星期几,比如公元1年1月1日是星期一。然后一天一天模拟,算出日期是星期几。这种方法容易理解,但是实现起来代码可能比较长。

  • 通过年份,月份,天数进行累加

  • 核心:ans += 366 % 7 ;ans % = 7;

  • 代码:

    c++
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    string weekday[7] = { "Monday","Tuesday" ,"Wednesday","Thursday","Friday","Sunday" };
    int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31};
    bool year(int y) {
    	return  ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
    }
    
    int whatday(int y, int m, int d) {
    	int ans = 0;
    	for (int i = 1; i < y; i++) {
    		if (year) {
    			ans += 366 % 7;  //一周7天,计算剩下多少个不满一周的;
    			ans %= 7;        //多个不满一周的组成一周后剩下几天;
    		}
    		else {
    			ans += 365 % 7;
    			ans %= 7;
    		}
    	}
    	for (int i = 1; i < m; i++) {
    		if (year) {
    			days[2] = 29;
    			ans += days[i] % 7;
    			ans %= 7;
    		}
    		else {
                days[2] = 28;
    			ans += days[i] % 7;
    			ans %= 7;
    		}
    	}
    	ans += (d - 1) % 7;
    	ans %= 7;
    	return ans;
    }
    int main() {
    	int y, m, d;
    	cin >> y >> m >> d;
    
    	cout << weekday[whatday(y, m, d)] << endl;
    	return 0;
    }

  • 除此之外,有一个公式可以快速地根据日期计算这一天是星期几,这被称为蔡基姆拉尔森计算公式。假设星期为w,年份为y,月份为m,日期为d w=(d+2 * m+3 * (m+1) / 5 + y + y / 4 - y / 100 + y / 400 ) % 7然后把计算出来的 w 加上 1 就是真正的星期几了。

  • 注意每年的1,2月要当成上一年13,14月计算,上述的除法均为整除

  • 代码

  • c++
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    string weekday[7] = { "Monday","Tuesday" ,"Wednesday","Thursday","Friday","Sunday" };
    int whatday(int y, int m, int d) {
    	if (m <= 2) {
    		m += 12;
    		y--;
    	}
    	return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
    }
    int main() {
    	int y, m, d;
    	cin >> y >> m >> d;
    	cout << weekday[whatday(y, m, d)] << endl;
    	return 0;
    }

例子2:恋爱纪念日

  • k天后是什么时候

    • 输入格式 输入4个整数y,m,d,k表示他们在一起的日期,保证是一个1900年1月1日以后的日期,xx想知道他们的k(0<k<10000)天纪念日。
    • 输出格式 输出格式按照yyyy-mm-dd的格式输出天纪念日的日期。月份和天数必须各输出2位。保证最后答案年份不超过4位
  • 代码

    c++
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    bool year(int y) {
    	return  ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
    }
    void whatday(int& y, int& m, int& d, int& k) {
    	for (int i = 1; i <= k; i++) {
    		if (year(y)) {
    			days[2] = 29;
    		}
    		else {
    			days[2] = 28;
    		}
    		d++;
    		if (d == days[m] + 1) {
    			d = 1;
    			m++;
    		}
    		if (m == 13) {
    			m = 1;
    			y++;
    		}
    	}
    }
    int main() {
    	int y, m, d, k;
    	cin >> y >> m >> d >> k;
    	whatday(y, m, d, k);
    	printf("%04d-%02d-%02d\n", y, m, d);
    	return 0;
    }

例子3:节假日

  • 日历有 阳历(公历) 和阴历(农历) 之分。每年都有法定节假日,这些分成三类: 双休、阳历节假日、阴历节假日。
  1. 双休
    1. 周六和周日2天
  2. 阳历节假日
    1. 元旦:阳历每年1月1日,放假1天
    2. 劳动节:阳历每年5月1日,放假1天
    3. 国庆节:阳历每年10月1日,放假3天
    4. 圣诞节:阳历每年12月25日,放假1天
  3. 阴历节假日
    1. 春节:阴历每年1月1日,放假3天
    2. 清明节:阳历每年4月4-6日之间的某天,放假1天
    3. 端午节:阴历每年5月5日,放假1天
    4. 中秋节:阴历每年8月15日,放假1天
  • 当节假日和双休重合时,双休 不延后也不提前保证节假日之间不会重合。现在给你某年的所有阴历节假日的阳历日期,以及当年的1月1日是星期几,请你计算出这一年(阳历1月1日到12月31日)放了多少天假(包括双休、阳历节假日和阴历节假日)

  • 输入格式: 第一行输入年份y(1900<y<2050) 接下来4行,每行输入两个整数m,d依次表示春节、清明节、端午节和中秋节的阳历日期。 最后一行一个整数表示当年1月1号是星期几(一周内的第几天,每周从星期一开始计数,即星期一为第一天)

  • 输出格式: 输出天数

  • 代码:

    c++
    #define _CRT_SECURE_NO_WARNINGS 1
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    int mm[10] = { 1,5,10,10,10,12 };
    int dd[10] = { 1,1,1,2,3,25 };
    int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    string weekday[7] = { "Monday","Tuesday" ,"Wednesday","Thursday","Friday","Sunday" };
    bool year(int y) {
    	return  ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
    }
    
    void nextday(int& y, int& m, int& d) {
    	d++;
    
    	if (d == days[m] + 1) {
    		d = 1;
    		m++;
    	}
    }
    int main() {
    	int y, w, m, d, sf;
    	int ans;
    	cin >> y;
    	for (int i = 6; i <= 9; i++) {
    		cin >> mm[i] >> dd[i];
    	}
    	cin >> w; //星期几
    	if (year(y)) {
    		days[2] = 29;
    	}
    	else {
    		days[2] = 28;
    	}
        //初始化
    	m = 1;
    	d = 1;//元旦
    	sf = 0; //表示春节
    	ans = 0;
    	while (m < 13) {
    		if (m == mm[6] && d == dd[6]) {//6号位 春节  春节不在其他假期里
    			ans++;
    			sf = 2; //春节还有2天假期
    		}
    		else if (sf) { // 春节已经在其他假期里
    			ans++;
    			sf--;
    		}
    		else if (w == 6 || w == 7) {//周末
    			ans++;
    		}
    		else {
    			for (int i = 0; i < 10; i++) {
    				if (m == mm[i] && d == dd[i]) {//遍历全部日期
    					ans++;
    					break;
    				}
    			}
    		}
    		nextday(y, m, d);//下一天
    		w++;
    		if (w == 8) {
    			w = 1;
    		}
    	}
    	cout << ans << endl;
    	return 0;
    }

练习

  • 输入格式 输入仅一行,为字符串s(长度不超过 10000)

  • 输出格式 输出s中最后一个单词的长度。

  • 代码

    c++
    #include <cstring>
    #include<cstdio>
    
    char  s[1005];
    int main() { 
    	while (scanf("%s", s) != EOF);
    	printf("%d\n", strlen(s));
    	return 0;
    }
  • 疑惑:

    vs sudio 不能CTRL + Z 或 CTRL + Z 跳出循环

方法学习

  • sort 是一个C++已经为我们实现好的工具,当我们要用它时,需要先引入一个算法的库<algorithmnm>

  • sort 可以排序任何类型的元素,包括我们自己定义的结构体。

  • sort(arr,arr+x); 排序arr开头元素到第x个元素,一般比下标多写一个;

  • sort(arr+i,arr+j) 排序arr[i]到arr[j-1],其他元素位置保持原来的位置

  • 例子

    c++
    //默认排序 从小到大
      int main() {
      	int arr[] = { 4,2,5,3,1 };
      	int n = sizeof(arr) / sizeof(arr[0]);
      	sort(arr, arr + 5);
      	for (int i =0; i < n; i++) {
      		cout << arr[i];
      	}
       }

排序方式

自带函数

从大到小 sort(arr,arr+5,greater<int>())

例子

小红所在的班级进行了数学考试,老师请小红同学帮忙进行名次排序和各分数段的人数统计工作。 现要求如下:将N名同学的考试成绩放在A数组中,各分数段的人数存到 B数组中: 成绩为100的人数存到B[1] 中, 成绩为90到99的人数存到 B[2] 中, 成绩为80到89的人数存到 B[3]中, 成绩为70到79的人数存到 B[4]中, 成绩为60到69的人数存到 B[5] 中, 成绩为60分以下的人数存到 B[6] 中.

  • 输入共有两行: 第一行:为小红所在班级的人数N(其中1<N <30) ; 第二行:为个用1个空格隔开的数学分数(其中分数为100及以内正整数)
  • 输出若干行: 分数从高到低 各分段的人数

代码

c++
#include <iostream>
#include<algorithm>
using namespace std;
int  A[35];
int  B[7];

int main() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> A[i];
	}
	sort(A, A + n, greater<int>());
	for (int i = 0; i < n; i++) {
		cout << A[i] << endl;
	}
	for (int i = 0; i < n; i++) {
		if (A[i] == 100) {
			B[1]++;
		}
		else if (A[i] >= 90) {
			B[2]++;
		}
		else if (A[i] >= 80) {
			B[3]++;
		}
		else if (A[i] >= 70) {
			B[4]++;
		}
		else if (A[i]>=60) {
			B[5]++;
		}
		else {
			B[6]++;
		}
	}
	for (int i = 1; i <= 6; i++) {
		cout << B[i]<<" ";
	}
	cout << endl;
	return 0;
}

构造排序方法

c++
//从大到小
bool cmp (int x,int y){
    return x > y;
}

例子:奖学金

某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前 5 名学生发奖学金。

期末,每个学生都有 3 门课的成绩:语文、数学、英语。

先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面,这样,每个学生的排序是唯一确定的。

任务:先根据输入的 3 门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名学生的学号和总分。

注意,在前 5 名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。

c++
#include <iostream>
#include <algorithm>
#include <vector>

namespace std;

struct Student {
    int StudentId;
    int ChineseScore;
    int MathScore;
    int EnglishScore;
    int IntotalScore;
};

bool compare(const Student& a, const Student& b) {
    if (a.IntotalScore != b.IntotalScore)
        return a.IntotalScore > b.IntotalScore;
    
    if (a.ChineseScore != b.ChineseScore)
        return a.ChineseScore > b.ChineseScore;
    
    return a.StudentId < b.StudentId;
}

int main() {
    int n;
    cin >> n;
    vector<Student> students(n);

    for (int i = 0; i < n; i++) {
        cin >> students[i].ChineseScore >> students[i].MathScore >> students[i].EnglishScore;
        students[i].StudentId = i + 1;
        students[i].IntotalScore = students[i].ChineseScore + students[i].MathScore + students[i].EnglishScore;
    }

    sort(students.begin(), students.end(), compare);

    for (int i = 0; i < 5 && i < n; i++) {
        cout << students[i].StudentId << " " << students[i].IntotalScore << endl;
    }

    return 0;
}

枚举

  • 枚举就是根据提出的问题,一-列出该问题的所有可能的解,并在逐一列出的过程中,检验每个可能解是否是问题的真正解,如果是就采纳这个解,如果不是就继续判断下一个枚举法一般比较直观,容易理解,但由于要检查所有的可能解,因此运行效率较低能够用枚举法解决的题目往往是最简单的一类题目。这种题目具有以下特点:
    • 解枚举范围是有穷的。
    • 检验条件是确定的。

例子1:年龄差

  • 某君说:“我的年龄是个两位数,我比儿子大 27 岁,如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”

  • 请你计算:某君的年龄一共有多少种可能情况?

  • 我们来分析一下这道题。题里给出某君的年龄是两位数,那么年龄的取值范围是[10-99]内的整数检验条件也是确定的,只要把枚举的年龄的个位与十位交换,如果发现比原数字刚好小27,那么它就是真正的解。

  • 代码

    c++
    #include <iostream>
    #include<algorithm>
    using namespace std;
    int main() {
    	int flag = 0;
    	for (int i = 10; i <= 99; i++) {
    		if (i - (i % 10 * 10 + i / 10) == 27) {
    			flag++;
    			cout << i <<" ";
    		}
    	}
    	cout << endl;
    	cout << flag << endl;
     }

例子2:水仙花数

水仙花数(Narcissistic number)也被称为超完全数字不变数、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数,水仙花数是指一个 3 位数,它的每个数位上的数字的 3次幂之和等于它本身。例如:1^3^ + 5^3^+ 3^3^ = 153。

求所有的水仙花数

c++
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main() {
	int a, b, c;
	for (int i = 100; i <= 999; i++) {
		a = i / 100;
		b = i % 100 / 10;
		c = i % 10;

		int sum = a * a * a + b * b * b + c * c * c;

		if (sum == i) {
			cout << i << endl;
		}
	}
	return 0;
}

例子3:质数

c++
#include<iostream>
using namespace std;

int main() {
	int n, m;
	cin >> n >> m;

	for (int i = n; i <= m; i++) {
		bool is_prime = true;
		for (int j = 2; j < i; j++) {
			if (i % j == 0) {
				is_prime = false;
				break;
			}
		}
		if (is_prime) {
			cout << i << " YES" << endl;
		}
		else {
			cout << i << " NO" << endl;
		}
	}
	return 0;
}

例子4:回文数各个位数之和等于n

回文数范围为10^5^——10^6^

c++
#include<iostream>
using namespace std;
int n;
int dight[6];
bool judge(int x) {
	int m = 0, sum = 0;
	while (x) {
		dight[m++] = x % 10;
		sum += x % 10;
		x /= 10;
	}
	if (sum != n) {
		return false;
	}
	for (int i = 0; i < m / 2; i++) {
		if (dight[i] != dight[m - 1 - i]) {
			return false;
		}
	}
	return true;
}
int main() {
	bool flag = false;
	int count = 0;
	cin >> n;
	for (int i = 10000; i <= 100000; i++) {
		if (judge(i)) {
			cout << i << endl;
			count++;
			flag = true;
		}
	}
	cout << count << endl;
	if (!flag) {
		cout << -1 << endl;
	}
	return 0;
}

练习1:拉格朗日定理

四平方和,拉格朗日定理

每个正整数都可以表示为至多4个正整数的平方和。如果把0包括进去,就正好可以表示为4个数的平方和。

求出字典序最小的一组解 a,b,c,d

c++
#include<iostream>
using namespace std;
int main(){
	
	int n, d;
	cin >> n;
	for (int a = 0; a * a <= n; a++) {
		for (int b = a; a * a + b * b <= n; b++) {
			for (int c = b; a * a + b * b + c * c <= n; c++) {
				d = sqrt(n - (a * a + b * b + c * c));
				if (a * a + b * b + c * c + d * d==n) {
					cout << a << " " << b << " " << c << " " << d << endl;
					return 0;
				}
			}
		}
	}
	return 0;
}

练习2:最大连续子集和

c++
#include<iostream>
using namespace std;
int a[105];
int main(){
	int n;
	int sum, ans;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	sum = 0;
	ans = 0;
	for (int i = 0; i < n; i++) {
		sum = 0;
		for (int j = i; j < n; j++) {
			sum += a[j]; 
			if (sum > ans) {
				ans = sum;
			}
		}
	}
	cout << ans<<endl;
	return 0;
}

常用STL

有些时候想开一个数组,但是却不知道应该开多大长度的数组合适,因为我们需要用到的数组可能会根据情况变动。这时候我们就需要用到动态数组。所谓动态数组,也就是不定长数组,数组的长度是可以根据我们的需要动态改变的。动态数组的实现也不难,但是在 C++ 里面有已经写好的标准模板库Standard Template Librarv,就是我们常说的 STL 库,实现了集合、映射表、栈、队列等数据结构和排序、查找等算法。我们可以很方便地调用标准库来减少我们的代码量

vector 动态数组

函数 C++ vector | 菜鸟教程

C++中动态数组写作vector,C语言中没有标准库,这也是为什么参加比赛推荐用C++而不用C的原因

引用库

#include<vector>

构造

构造一个vector 的语句为: vector<T> a

这样我们定义了一个名为 a 的储存类型数据的动态数组。其中是我们数组要储存的数据类型,可以是 intfloatdouble、或者其他自定义的数据类型等等。初始的时候 a 是空的。比如vector <int> a定义了一个储存整数的动态数组a。

插入元素

通过push_back()方法在数组最后面插入一个新的元素

删除

通过pop_back()方法在数组最后的一个元素

获取长度并且访问元素

通过size()获取数组长度 通过[]操作直接访问 vector 中的元素

清空

调用 clear() 方法就可清空 vector并不会清空开的内存。

新构建一个,用swap()方法与其交换可以清空vector的内存

c++
vector<int> a;
vector<int>().swap(a);
c++
#include<iostream>
#include<vector>
using namespace std;
vector<int> a;
int main() {
	cout << "初始化状态" << endl;
	cout << "size:" << a.size();
	for (int i = 0; i < a.size(); i++) {
		cout << a[i] << endl;
	}
	cout << endl;

	cout << "尾插" << endl;
	a.push_back(1);
	a.push_back(2);
	a.push_back(3);
	cout << "size:" << a.size()<<endl;
	for (int i = 0; i < a.size(); i++) {
		cout << a[i] << endl;
	}
	cout << endl;

	cout << "尾删" << endl;
	a.pop_back();
	cout << "size:" << a.size()<<endl;
	for (int i = 0; i < a.size(); i++) {
		cout << a[i] << endl;
	}
	cout << endl;

	cout << "清除" << endl;
	a.clear();
	cout <<"size:" << a.size()<<endl;
	for (int i = 0; i < a.size(); i++) {
		cout << a[i] << endl;
	}
	cout << endl;

	cout << "去内存" << endl;
	vector<int>().swap(a);
	cout << "size:" << a.size();
	for (int i = 0; i < a.size(); i++) {
		cout << a[i] << endl;
	}
}

vector():创建一个空vector

vector(n):创建一个vector,元素个数为n,mor

vector(n,x):创建一个vector,元素个数为n,且值均为x

vector(const vector&):复制构造函数

vector(begin,end):复制(begin,end)区间内另一个数组的元素到vector中`

二维动态数组

vector<vector<int> > b


set 集合

引用库

#include<set>using namespace std;

构造

set<T> s

这样我们定义了一个名为s的、储存类型数据的集合,其中T是集合要储存的数据类型。初始的时候 s 是空集合。比如set<int> aa set<string> bbb 等等。

插入

insert()

C++ 中用insert()函数向集合中插入一个新的元素。注意如果集合中已经存在了某个元素,再次插入不会产生任何效果,集合中是不会出现重复元素的。

删除

erase()

C++ 中通过erase()函数删除集合中的一个元素,如果集合中不存在这个元素,不进行任何操作。

断元素是否存在

count()

C++ 中如果你想知道某个元素是否在集合中出现,你可以直接用 count()函数。如果集合中存在我们要查找的元素,返回1,否则会返回0。

遍历元素

C++ 通过迭代器可以访问集合中的每个元素,迭代器就好像一根手指,指向 set 中的某个元素。通过操作这个手指,我们可以改变它指向的元素。通过 * (解引用运算符,不是乘号的意思)操作可以获取迭代器指向的元素。通过++操作让送代器指向下一个元素,同理-- 操作让迭代器指向上一个元素。

迭代器的写法比较固定,set<T>::iterator it 就定义了一个指向 set<T>这种集合的送代器 it,T是任意的数据类型。其中::iterator 是固定的写法

begin 函数返回容器中起始元素的迭代器,end函数返回容器的尾后迭代器。

注意,在C++中遍历set 是从小到大遍历的,也就是说 set 会帮我们排序的。

set和结构体

c++
struct Node {
	int x, y;
	bool operator<(const Node& rhs) const {
		if (x == rhs.x) {
			return y < rhs.y;
		}
		else {
			return x < rhs.x;
		}
	}
};

operator<表示我们要重载运算符<,可以看成是一个函数名。rhsright hand side的简称,有右操作数的意思,这里我们定义为一个const引用。因为该运算符重载定义在结构体内部,左操作数就当前调用operator<的对象 特别要注意,不要漏掉最后的constconst 函数表示不能对其数据成员进行修改操作,并且 const 对象不能调用非 const 成员函数,只允许调用 const 成员函数。 上面重载规定了排序方式为,优先按照 x从小到大排序,如果x相同,那么再按照 y从小到大排序。经过了<运算符重载的结构体,我们就可以比较两个Node 对象的大小了,因此可以直接储存在set中了。

&避免建临时变量,const防止因传&而改变

map 映射

引用库

#include<map>using namespace std;

构造

map<T1,T2> m;

在C++中,我们构造一个map 的语句为: map<T1,T2>m;。这样我们定义了一个名为m的从T1类型到T2类型的映射。初始的时候m是空映射。

比如 map <string,int> m构建了一个字符串到整数的映射,这样我们可以把一个字符串和一个整数关联起来。

插入

pair<T1,T2> p;用于保存

insert(make_pair(T1,T2))

我们向映射中加入新映射对的时候就是通过插入 pair 来实现的。如果插入的 key 之前已经存在了,将不会用插入的新的 value替代原来的 value,也就是这次插入是无效的。

访问

m[ ]

C++ 中访问映射和数组一样,直接用[]就能访问。比如 dict["Tom"]就可以获取"Tom"的班级了。而这里有一个比较神奇的地方,如果没有对"Tom"做过映射的话,此时你访问dict["Tom"],系统将会自动为"Tom"生成一个映射,其value为对应类型的默认值(比如int的默认值是0,string的默认值是空字符串)。

并且我们可以之后再给映射赋予新的值,比如 dict["Tom"] = 3,这样为我们提供了另一种方便的插入手段。实际上,我们常 常通过下标访问的方式来插入映射,而不是通过用insert 插入一个pair 来实现。

遍历

map<T1,T2> m::iterator it = m.begin();it !=m.enf(); it++;

在C++中遍历map 是按照关键字从小到大遍历的,这一点和 set 有些共性。

练习

1锯齿矩阵

c++
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;
vector<int> a[10005];
int main() {
	int n, m;
	int x, y;
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		cin >> x >> y;
		a[x].push_back(y);
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < a[i].size(); j++) {
			if (j != a[i].size() - 1) {
				cout << a[i][j] << " ";
			}
			else {
				cout << a[i][j];
			}
		}
        cout<<endl;
	}
	return 0;
}
markdown
3 12
1 3
2 2
2 3
2 4
3 1
3 6
1 5
1 2
1 6
3 2
3 7
1 1

3 5 2 6 1
2 3 4
1 6 2 7

Released under the MIT License.