目录
二:STL:具体语法不写了,网上多的是,这里链接是凌乱之风大佬的总结
一:C++零散知识
1:cout输出小数点位数:
//头文件加入#include <iomanip>
#include<iostream>
#include<iomanip>
using namespace std;
const float pi = 3.1415926;
int main()
{
cout.setf(ios::fixed);
cout<<fixed<<setprecision(9)<<pi<<endl;//以固定位数显示
cout.unsetf(ios::fixed);
cout<<setprecision(9)<<pi<<endl;//以是几位数输出
return 0;
}
2:cout关闭同步
std::ios::sync_with_stdio(false);
3:putchar()吸收空格很有用
4:冒泡排序我最喜欢,但经常超时,快速排序比冒泡快。
二:STL:具体语法不写了,网上多的是,这里链接是凌乱之风大佬的总结
个人感觉Acm就是C语言+STL,学会使用STL非常重要
STL对程序简化非常重要
1:vector:
vector相比于其他动态序列容器,访问元素时更加高效,在末尾添加或者删除元素时,更加高效,但是如果不在末尾添加或者删除元素,效率更低。
vector经常用作数组使用,再不确定元素个数时能够很好的节省空间,在一些题目中,需要把不确定个数的数据输出在同一行,中间用空格隔开,这时用vector先记录再一次性输出比较方便。
vector声明和初始化中,可以用数组元素初始化vector,也可以部分初始化,比较灵活,
vector在内存中,就像二维数组一样,是一个连续的数组,在C++11中,可以返回一个指针指向这个数组 int*p = vec.data();
vector中的元素可以像普通的数组那样用cin>>;cout<<a[i]一样输入输出,也可以用迭代器进行输出vector<int>::iterator迭代器比较灵活,不但可以表示元素位置,还可以在容器中前后移动。除此之外,vector还能使用指针形式间接访问
#include<iostream>
#include<vector>
using namespace std ;
int main()
{
vector<int> a(10, 1) ;
for(int i = 0;i<10;i++)
{
cin>>a[i];
}
vector<int>::iterator t ;
for(t=a.begin(); t!=a.end(); t++)
{
cout<<*t<<" " ;
}
return 0 ;
}
vector可以增加维数,但是维数多了就难以灵活控制。
vector< vector<int> > b(10, vector<int>(5));
同时vector可以实现邻接表建图
山东理工大学OJ3 广度优先搜索练习之神奇的电梯 就可以使用vector建图,然后用BFS搜索;
#include<bits/stdc++.h>
using namespace std;
int bfs(int i, int as);
class node
{
public:
int num;
int step;
};
vector<int>pho[300];
int arr[300];
int n, m, q;
int main()
{
int num, pos, to;
while (cin >> n >> m >> q)
{
for (int i = 0; i < 205; i++)
pho[i].clear();
for (int i = 0; i < m; i++)
{
cin >> pos >> num;
while (num--)
{
cin >> to;
pho[pos].push_back(to);
}
}
int as;
while (q--)
{
cin >> as;
memset(arr, 0, sizeof(arr));
cout << bfs(1, as) << endl;
}
}
return 0;
}
int bfs(int i, int as)
{
arr[i] = 1;
node p = {i, 1};
queue<node> q;
q.push(p);
while (!q.empty())
{
node temp = q.front();
q.pop();
if (temp.num == as)
return temp.step;
vector<int>::iterator it;
for (it = pho[temp.num].begin(); it < pho[temp.num].end(); it++)
{
node t = {*it, temp.step + 1};
if (!arr[*it])
{
arr[*it] = 1;
q.push(t);
}
}
}
return -1;
}
2:set
无序且不能重复,set封装了很多复杂的数据结构算法和数据结构操作,定义和写法和大部分STL差不太多,set访问只可以使用迭代器访问,主要是用来去重并按升序排序。
应用举例:SDUTOJ Message Flood
这道题非常典型,因为不用STL用其他排序都会超时
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,i,j,len;
char s[30];
while(scanf("%d",&n)!=EOF&&n)
{
set<string>name;
set<string>::iterator it;
scanf("%d",&m);
getchar();
for(i=0; i<n; i++)
{
gets(s);
len=strlen(s);
for(j=0; j<len; j++)
{
s[j]=towlower(s[j]);
}
name.insert(s);
}
for(i=0; i<m; i++)
{
gets(s);
len=strlen(s);
for(j=0; j<len; j++)
{
s[j]=towlower(s[j]);
}
if(name.count(s))
name.erase(s);
}
printf("%d\n",name.size());
}
return 0;
}
3:map :
map定义和其他STL容器不一样,有尖括号内有两个类型变量,map访问方式也有下表和迭代器访问,map和set都是使用红黑树实现,在建立映射过程中都会事先从小到大排序功能,C++11中增加了undordered_map,不按key排序只按键排序,速度比map快。
map用指针会出错,一般不用。python的map比c++的map去重快,因为python是hash map.
我对map的理解是,map大致相当于一个二维数组,或者是两个一维数组
示例:SDUT OJ Message Flood
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
int i,j;
while (cin>>n&&n!=0)
{
cin>>m;
map<string,int>mp;
string s;
for (i=1; i<=n; i++)
{
cin>>s;
for (j=0; j<s.size(); j++)
{
s[j]=towlower(s[j]);
}
mp[s]++;
}
for (i=1; i<=m; i++)
{
cin>>s;
for (j=0; j<s.size(); j++)
{
s[j]=towlower(s[j]);
}
mp.erase(s);
}
cout<<mp.size()<<endl;
}
return 0;
}
4:queue
初始化时必须要有数据类型,容器可省略,省略时则默认为deque 类型,queue是先进先出的容器,在实现广度优先搜索时,可以不用自己手动实现一个队列,使用queue作为代替可以提高程序的准确性,在使用front()和pop()函数前,必须用empty()判断队列是否为空。
注意:不能用vector容器初始化queue
因为queue转换器要求容器支持front()、back()、push_back()及 pop_front(),说明queue的数据从容器后端入栈而从前端出栈。所以可以使用deque和list对queue初始化,而vector因其缺少pop_front(),不能用于queue。
应用:SDUT OJ 2087 离散事件模拟-银行管理
我没写出这个题来 但我知道是队列
5:priority_queue:
优先队列,队首元素一定是优先级最高的那一个,可以以用来解决一些贪心难问题
6:stack
一个先进后出的容器;只能够用top()来访问栈顶的元素,stack一般用来模拟实现一些递归操作,用栈模拟递归造作可以避免递归层数过深导致程序崩溃。
在使用pop()和top()函数之前必须先使用empty()函数判断栈是否为空。
应用:
SDUT OJ 数据结构实验之栈与队列八:栈的基本操作
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,m,n;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
stack<int>s;
char x;
int a,top=1;
while(n--){
printf("%s",x);
if(x=='A'){
if(s.empty()) cout <<"E"<<endl;
else cout <<s.top()<<endl;
}
else if(x=='O'){
if(s.empty()) cout <<"E"<<endl;
else {cout <<s.top()<<endl;s.pop();top--;}
}
else{
cin>>a;
if(top<=m) {s.push(a);top++;}
else cout <<"F"<<endl;
}
}
if(t!=0) cout <<endl;
}
return 0;
}
7:Pair
和map比较类似 map像是一个个Pair组合而成,简单而有用,一般是和map一起使用
例题: sdut oj 众数问题
#include<bits/stdc++.h>
using namespace std;
const pair<int,int> a;
const pair<int,int> b;
bool cmp(pair<int,int> a,pair<int,int> b);
int main()
{
int m,n;
map<int,int>k;
cin>>m;
for(int i=0; i<m; i++)
{
scanf("%d",&n);
k[n]++;
}
map<int,int>::iterator it = max_element(k.begin(),k.end(),cmp);
cout<<it->first<<endl<<it->second<<endl;
return 0;
}
bool cmp(pair<int,int>a,pair<int,int>b)
{
return a.second<b.second;
}
8: next_permutation
next_permutation(first, last) 用于求序列[first,last)元素全排列中一个排序的下一个排序
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[3] = {0, 1, 2};
do
{
for (int i = 0; i < 3; i++)
cout<<a[i]<<' ';
cout<<endl;
}
while (next_permutation(a, a + 3));
return 0;
}
三:数学入门
1:快速幂
求a^b mod m 的值。
把b进行二进制分解。
void quick_pow(int a,int b)
{
int ret = 1;
while(b)
{
if(b&1)ret = ret*a%mod;
b>>=1;
a=a*a%mod;
}
return ret;
}
2:欧几里得算法
就是求 gcd(x,y) d|x , d|y等价于d|(x-y),d|x 所以gcd(x,y)=gcd(x-y,y)=gcd(y,x%y) 显然每次取模后数字的大小至少折半(可以想一想为什么),所以复杂度是低于O(log max(x,y))级别的
int exgcd(int a,int b,int&x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int r = exgcd(b,a%b,x,y);
int temp = y;
y = x-(a/b)*y;
x=temp;
return r;
}
应用:NOIP2012 同余方程
求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解。 就是ax+by=1中x最小的正整数解。
四:DFS
1:DFS
解决问题:八皇后,递归求全排列,递推求全排列
个人感觉比较难,重点是找到边界
void dfs(...) { //递归参数:当前枚举到哪一步
if(到达终点) {
记录答案
return;
}
if(当前状态不合法) return;
if(达到剪枝条件) return;
for(...) { //枚举状态
if(将要访问的状态不合法) continue;
操作
标记已经访问
dfs(下一步);
(还原标记) //回溯法
}
}
八皇后:
#include<bits/stdc++.h>
using namespace std;
int ans[10], vis[3][20];
void dfs(int now) {
if(now == 9) {
for(int i = 1; i <= 8; i++) cout << ans[i] << " ";
cout << "\n";
return;
}
for(int i = 1; i <= 8; i++) {
if(vis[0][i] || vis[1][now + i] || vis[2][now - i + 8]) continue;
ans[now] = i;
vis[0][i] = 1; vis[1][now + i] = 1; vis[2][now - i + 8] = 1;
dfs(now + 1);
vis[0][i] = 0; vis[1][now + i] = 0; vis[2][now - i + 8] = 0;
}
}
int main() {
dfs(1);
return 0;
}
五:综述
革命尚未成功,同志继续努力。