STL在算法比赛中简单应用
STL基础 和 简单的贪心问题
STL(Standard Template Library) 即 标准模板库。 它包含了诸多在计算机科学领域里所常用的基本数据结构和算法。这些数据结构可以与标准算法一起很好的工作。
这里我们主要是为了学会如何使用,如果想了解更多,可以参考《c++ primer 第五版》
vector
vector 就是一个 不定长数组。它把一些常用的操作 “封装” 在了vector类型内部。
vector是一个模板类,所以需要vector<int> a 或者 vector<string> b 这样的方式来声明一个 vector对象。
vector<int> 类似于 int a[] 的整数数组, 而vector<string> b 相当于 string b[] 的字符串数组。
下面用代码介绍,常用的操作:
#include <iostream>
#include <vector> //使用vector需要引入这个头文件
#include <iterator> //这是使用迭代器需要引入的头文件
using namespace std;
int main()
{
vector<int> v; //定义一个vector容器 //以下操作向 v对象中,连续添加5个元素 1, 2, 3, 4, 5
v.push_back(); //向容器添加元素1
v.push_back();
v.push_back();
v.push_back();
v.push_back(); //遍历向量的元素( 这里不需要c++11的标准, 蓝桥杯应该也是支持的), C遍历的写法
cout << "----------------------- \n遍历操作: \n";
for (unsigned i = ; i < v.size(); i++)
{
cout << v[i] << endl;
} vector<int>::iterator beg = v.begin(); //指向容器的第一个元素
vector<int>::iterator ed = v.end(); //指向容器 尾元素的 下一个位置!注意是下一个位置 cout << "----------------------- \n迭代器操作: \n";
for (vector<int>::iterator it = beg; it != ed; ++it)
{
cout << *it << endl;
}
//这里演示c++11的简单方法, 蓝桥杯貌似不支持
cout << "--------------------- \nc++11标准: \n";
//这里使用的叫做范围for循环, 不需要指定类型,由编译器自动完成
for (auto &e : v)
{
cout << e << endl;
} // 顺序容器的一些操作
cout << "\n容器的元素的size: " << v.size() << endl; cout << "\n容器删除指定位置元素, " ;
//删除第4个元素, vector的删除和插入元素操作效率都比较低, 不适合大批操作
v.erase(v.begin() + ); cout << "删除第4个元素后容器: \n";
for (auto &e : v) {
cout << e << endl;
} //与vector有关的其他操作,以及类似的还有链表list,可以参考:
//http://zh.cppreference.com/w/cpp/container/vector return ;
}
string类
可以动态存储字符串,并且集成了一堆对字符串的操作
#include <iostream>
#include <string>
using namespace std;
int main()
{
/*---------------------string容器的一些操作-----------------------*/
string str1 = "Hello Douzi"; // string的几种构造方法
string str2("Hello World");
string str3(str1, ); // 从str1下标6开始构造, str3 == 'Douzi' string str4 = str2.substr(, ); // 求子串: str4 -> Hello
string str5 = str2.substr(); // 求子串: str5 -> World
string str6 = str2.substr(, ); // 求子串: str6 -> World
// string str7 = str2.substr(12); // 抛异常: out_of_range
string str8 = str2.replace(, , "Game"); // 替换:str8 -> Hello Game 从位置6开始,删除5个字符,并替换成"Game"
string str9 = str2.append(", Hi girl"); // 追加字符串: str9 -> Hello World, Hi girl
// 查找字符串 : pos1 -> 6 ,返回第一次出现字符串的位置,如果没找着,则返回npos
auto pos1 = str1.find("Douzi");
cout << "Douzi 第一次出现在str1中位置: " << pos1 << endl;
string ss1 = "Dou";
string ss2 = "zi"; if (ss1 == ss2)
{
cout << "ss1 == ss2" << endl;
}
else if (ss1 < ss2)
{
cout << "ss1 < ss2" << endl;
}
else if (ss1 > ss2)
{
cout << "ss1 > ss2" << endl;
} string ss3 = ss1 + ss2;
cout << "ss1 + ss2 = " << ss3 << endl;
cout << "ss2 + ss1 = " << ss2 + ss1 << endl; return ;
}
set (关联容器)
是用 二查搜索树 维护集合的容器;
简单的说就是,里面存放的数据: 每个元素最多只出现一次,且里面元素 有序 (可以自定义排序)
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
#include <cstdio>
using namespace std;
int main()
{
//声明
set<int> s; //插入元素
s.insert();
s.insert();
s.insert();
s.insert();
s.insert(); // c++11, 蓝桥杯不支持
for (auto &e : s) {
cout << e << endl;
}
cout << "迭代器遍历: \n";
//迭代器, 蓝桥杯支持
for (set<int>::iterator it = s.begin(); it != s.end(); ++it)
{
cout << *it << endl;
}
//集合的元素的不重复的
s.insert();
cout << "插入一个重复的元素之后: " << endl;
for (const auto& e : s) {
cout << e << endl;
} //查找元素
set<int>::iterator ite; ite = s.find();
cout << "查找元素1 : ";
if (ite == s.end()) {
printf("not found !");
}
else {
cout << "Found !" << endl;
} //删除元素
s.erase(); cout << "\n删除了元素1之后查找1: ";
//其他查找元素的方法
if (s.count() != ) {
cout << "Found !\n";
}
else {
cout << "Not found !\n";
} cout << "\n遍历所有元素: \n";
for (auto &e : s) {
cout << e << endl;
} return ;
}
map(关联容器)
map 是 维护键 和 键对应的值 的容器.
即是: 实现从 键 (key) 到 值(value) 的映射。map重载了
[]
运算符, map像 高级版的数组如: 可以用一个
map<string, int> mon_name
来表示 "月份名字到月份编号" 的映射, 然后用mon_name["july"] = 7
这样的方式来赋值。
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <cstdio>
using namespace std;
int main()
{
//声明(int为键, const char *为值)
map<int, const char*> m; //插入元素
m.insert(make_pair(, "ONE"));
m.insert(make_pair(, "TEN"));
m[] = "Hundred"; //查找元素
map<int, const char*>::iterator ite;
ite = m.find(); if (ite == m.end()) {
cout << "not found !" << endl;
}
else {
cout << ite->second << " is found " << endl;
} //另外一种查找方式
if (m.count() != ) {
cout << m[] << " is found \n";
}
else {
cout << "not found !\n";
} m.erase(); //遍历一遍所有元素
cout << "\n遍历所有元素: \n";
for (ite = m.begin(); ite != m.end(); ++ite) {
printf("%d: %s\n", ite->first, ite->second);
} cout << "\n范围for循环: \n";
for (const auto& e: m) {
cout << e.first << ": " << m[e.first] << endl;
} // 可以写一下这个简单题: http://lx.lanqiao.cn/problem.page?gpid=T411
return ;
}
stack
栈(Stack) 是支持 push 和 pop两种操作的数据结构。
push是在栈的顶端放入一组数据的操作。
pop 是从其顶端取出一组数据的操作。但他仅仅是 移除最顶端的数据,如果要访问最顶端的数据,需要使用 stack::top函数
#include <iostream>
#include <stack>
#include <cstdio>
using namespace std;
int main()
{
stack<int> s; //声明存储int类型的数据的栈
s.push(); //{} -> {1}
s.push(); //{1} -> {1, 5}
s.push(); //{1, 5} -> {1, 5, 3} cout << s.top() << endl; // s.pop(); //从栈顶移除{1, 5, 3} -> {1, 5}
cout << s.top() << endl; // s.pop(); //从栈顶移除{1, 5} -> {1}
cout << s.top() << endl; // s.pop();
if (s.empty()) {
cout << "栈为空\n";
} return ;
}
queue
队列是 先进先出 的数据结构
用push() 和 pop() 进行元素的入队和出队; front() 取队首元素 (但不删除)
队列在 BFS搜索的题目中会经常用到,需要会使用
#include <iostream>
#include <queue>
using namespace std;
int main()
{
queue<int> que; //声明存储int类型的数据的队列
que.push(); //{} -> {1}
que.push(); //{1} -> {1, 2}
que.push(); //{1,2} -> {1, 2, 3}
cout << que.front() << endl; // que.pop(); //从队首移除 {1,2,3} -> {2, 3}
cout << que.front() << endl; // que.pop(); //从队首移除 {2,3} -> {3}
cout << que.front() << endl; // que.pop();
if (que.empty()) {
cout << "队列为空\n";
} return ;
}
sort
c++ 自带的排序
#include <iostream>
#include <algorithm>
#include <functional>
#include <cstdio>
#include <string>
using namespace std;
struct Stu {
int score;
int rp;
string name; Stu(string name = "", int score = , int rp = ) :
name(name), score(score), rp(rp) {}
};
//按(分数+人品)升序 排序
bool cmp(const Stu& a, const Stu& b)
{
return (a.score + a.rp) < (b.score + b.rp);
}
int main()
{
int a[] = {, , , , , , , , , , , , }; cout << "降序: ";
sort(a, a + , greater<int>()); for (int i = ; i < ; i++) {
cout << a[i] << " ";
} cout << "\n\n升序: ";
sort(a, a + , less<int>()); for (const auto& e: a) {
cout << e << " ";
} cout << "\n\n";
//自定义排序
Stu s[] = {Stu("Douzi", , ), Stu("Baozi", , ), Stu("douzujun", , )};
sort(s, s + , cmp); for (int i = ; i < ; i++)
{
cout << s[i].name << ": " << s[i].score << " " << s[i].rp << endl;
} cout << endl; return ;
}
next_permutation
全排列问题
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX_N = ;
bool used[MAX_N];
int perm[MAX_N];
//生成{0,1,2,3....n-1}的 n! 排序
void permutation1(int pos, int n)
{
if (pos == n) {
/*这里编写要对perm进行的操作*/
for (int i = ; i < pos; i++)
cout << perm[i] << " ";
cout << endl;
return;
}
//针对perm的第pos个位置, 究竟使用0~n-1中哪个进行循环
for (int i = ; i <= n; i++) {
if (!used[i]) {
perm[pos] = i;
used[i] = true;
permutation1(pos + , n);
//返回之后把标志复位 -- 否则一次就结束了
used[i] = false;
}
}
return;
}
void solve2(int n)
{
int perm2[] = {, , }; do {
for (int i = ; i < n; i++) {
cout << perm2[i] << " ";
}
cout << endl;
} while (next_permutation(perm2, perm2 + n));
}
int main()
{
permutation1(, ); cout << "\n使用STL中的next_permutation: \n";
solve2();
}
往年蓝桥杯中用next_permutation能够快速解题的
观察下面的加法算式:
祥 瑞 生 辉
+ 三 羊 献 瑞
-------------------
三 羊 生 瑞 气
其中,相同的汉字代表相同的数字,不同的汉字代表不同的数字。
请你填写“三羊献瑞”所代表的4位数字(答案唯一),不要填写任何多余内容。(这是网上复杂的解法)
下介绍用 next_permutation 的简单写法
#include <iostream>
#include <algorithm>
using namespace std;
void solve()
{
int a[] = {, , , , , , , , , }; int b, c,
sum; do {
b = a[] * + a[] * + a[] * + a[];
c = a[] * + a[] * + a[] * + a[]; sum = a[] * + a[] * + a[] * + a[] * + a[]; if ( (c > ) && (b + c == sum) ) {
cout << c << endl;
} } while (next_permutation(a, a + ));
}
int main()
{
solve();
}
课后习题:
问题二(会用到DFS): 带分数 http://lx.lanqiao.cn/problem.page?gpid=T26
简单的贪心问题
硬币问题
有1元、5元、10元、50元、100元、500元的硬币各C1,C5,C10,C50,C100,C500枚。现在要用这些硬币来支付A元,最少 需要多少枚硬币?假设本题至少存在一种支付方案。
限制条件: 0<=C1,C5,C10,C50,C100,C500<=10的9次方 ; 0<= A <= 10的9次方
输入: C1 = 3 C2 = 2 C10 = 1 C50 = 3 C100 = 0 C500 = 2 A = 620
输出: 6(500元硬币1枚,50元硬币2枚,10元硬币1枚,5元硬币2枚,合计6枚)
解题思路: 优先选择最大金额的面额
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = + ;
//硬币的面值
const int V[] = {, , , , , };
//输入
int C[maxn]; // c[0] = C_1, C{1] = C_5....
int A; //支付A元
/*
3 2 1 3 0 2 620
*/
void solve()
{
int ans = ; for (int i = ; i >= ; i--)
{
int t = min(A / V[i], C[i]); //使用硬币i的枚数
A -= t * V[i]; //还需支付的金额
ans += t;
} printf("%d\n", ans);
}
void input()
{
for (int i = ; i < ; i++)
{
cin >> C[i];
}
cin >> A;
}
int main()
{
input();
solve();
}
类似联系:蓝桥杯 算法提高 快乐司机
题目链接: http://lx.lanqiao.cn/problem.page?gpid=T321
话说现在当司机光有红心不行,还要多拉快跑。多拉不是超载,是要让所载货物价值最大,特别是在当前油价日新月异的时候。司机所拉货物为散货,如大米、面粉、沙石、泥土...... 现在知道了汽车 核载重量为w,可供选择的物品的数量n。每个物品的重量为gi, 价值为pi。求汽车可装载的最大价值。(n<10000,w<10000,0<gi<=100,0<=pi<=100)
输入格式
输入第一行为由空格分开的两个整数n w 第二行到第n+1行,每行有两个整数,由空格分开,分别表示gi和pi
输出格式
最大价值(保留一位小数)
样例输入
5 3699 8768 3679 4375 947 35
样例输出
71.3解释:先装第5号物品,得价值35,占用重量7再装第4号物品,得价值36.346,占用重量29最后保留一位小数,得71.3
由这个解释可以看出来: 物品可以分开装载到车上,不一定是不够装就不装了,而是装上能装的部分
显然,既然可以散装,那么排序的时候,应该用单价来进行升序排序!即每次都优先选择,单价高的物品,当不够装的时候,将剩余的重量全部 用来给 当前单价最高的物品放置
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int maxn = + ;
struct Lorry {
float weight;
float value;
float pro;
Lorry(float w = , float v = , float pro = ) :
weight(w), value(v), pro(pro) {}
} lorry[maxn];
//按价值率降序排序
bool cmp(const Lorry& a, const Lorry& b)
{
return a.pro > b.pro;
}
void solve();
void solve()
{
int n;
float w; //物品数量, 核载重量
float ans = ;
scanf("%d", &n);
cin >> w;
for (int i = ; i < n; i++) {
cin >> lorry[i].weight >> lorry[i].value;
lorry[i].pro = lorry[i].value / lorry[i].weight;
}
//价值高的在前
sort(lorry, lorry + n, cmp); for (int i = ; i < n; i++)
{
if (w == ) break;
//w > l[i].weight 放心减就好了
if (w - lorry[i].weight > ) {
w -= lorry[i].weight;
ans += lorry[i].value;
} else {
//否则..全部用来给w, 还有剩余,单价最高嘛
ans += lorry[i].pro * w;
lorry[i].weight -= w;
w = ;
}
}
printf("%.1f\n", ans);
}
int main()
{
solve();
return ;
}
类似练习: Codevs 1621 混合牛奶
类似练习: Codevs 1052 地鼠游戏 http://codevs.cn/problem/1052/
关键:
游戏开始时,会在地板上一下子冒出很多地鼠(同时出现的) 来,然后等你用榔头去敲击这些地鼠,每个地鼠被敲击后,将会增加相应的游戏分值。问题是这些地鼠不会傻傻地等你去敲击,它总会在冒出一会时间后又钻到地板下面去(而且再也不上来),每个地鼠冒出后停留的时间可能是不同的,而且每个地鼠被敲击后增加的游戏分值也可能是不同,为了胜出,游戏参与者就必须根据每个地鼠的特性,有选择地尽快敲击一些地鼠,使得总的得分最大。
(敲击每个地鼠所需要的耗时是1秒),而且他还发现了游戏的一些特征,那就是每次游戏重新开始后,某个地鼠冒出来后停留的时间都是固定的,而且他记录了每个地鼠被敲击后将会增加的分值。于是,他在每次游戏开始后总能有次序地选择敲击不同的地鼠,保证每次得到最大的总分值。
输入描述 Input Description
输入包含3行,第一行包含一个整数n(1<=n<=100)表示有n个地鼠从地上冒出来,第二行n个用空格分隔的整数表示每个地鼠冒出后停留的时间,第三行n个用空格分隔的整数表示每个地鼠被敲击后会增加的分值(<=100)。每行中第i个数都表示第i个地鼠的信息。
输出描述 Output Description
输出只有一行一个整数,表示王钢所能获得的最大游戏总分值。
样例输入 Sample Input
5
5 3 6 1 4
7 9 2 1 5
样例输出 Sample Output
24
题解: 地鼠具有两个属性(时间, 分值),所以我考虑将地鼠设置为结构体, 包含时间和分值,将地鼠按照时间自定义升序排序。这里有点动态规划的意思,
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = + ;
struct Mice {
int value;
int time;
Mice(int v = , int t = ): value(v), time(t) {}
//需要对时间进行排序 -- 升序
friend operator < (const Mice& a, const Mice& b) {
return a.time < b.time;
}
} game[maxn];
int dp[maxn], ans;
void solve();
void solve()
{
int n;
memset(dp, , sizeof(dp));
cin >> n;
for (int i = ; i < n; i++) {
cin >> game[i].time;
}
for (int i = ; i < n; i++) {
cin >> game[i].value;
} //按照时间升序
sort(game, game + n);
for (int i = ; i < n; i++)
{
//从时间小的开始打
for (int j = game[i].time; j >= ; j--)
{
//game[i].time为当前最小的时间
//j为动态减小的时间
//比较"当前时间长的value+之前时间短的价值" 与 "当前时间长的value",更新j时间价值高的
dp[j] = max(dp[j], dp[j - ] + game[i].value);
//更新价值更高的值
ans = max(ans, dp[j]);
}
}
printf("%d\n", ans);
}
int main()
{
solve(); return ;
}
类似题目:
二分查找
文章参考了: 《c++ primer》、《算法竞赛入门经典》、《挑战程序设计竞赛》
以及谭兆飞学长的博客:http://www.jianshu.com/p/26d4d60233a
以及我自己的博客:http://www.cnblogs.com/douzujun/category/973918.html
STL在算法比赛中简单应用的更多相关文章
- LintCode2016年8月8日算法比赛----中序遍历和后序遍历构造二叉树
中序遍历和后序遍历构造二叉树 题目描述 根据中序遍历和后序遍历构造二叉树 注意事项 你可以假设树中不存在相同数值的节点 样例 给出树的中序遍历: [1,2,3] 和后序遍历: [1,3,2] 返回如下 ...
- STL 统计vector容器中指定对象元素出现的次数:count()与count_if()算法
1 统计vector向量中指定元素出现的次数:count()算法 利用STL通用算法统计vector向量中某个元素出现的次数:count()算法统计等于某个值的对象的个数. #include &quo ...
- C++ 基于STL的演讲比赛流程管理系统(sort算法+小型算法(accumulate)+内建函数对象+string字符串拼接+字符串截取+多个容器基础操作+与用户交互+文件的读写+保存+重建+整体文件数据的清空)
1 /* 2 比赛规则: 3 学校举行一演讲比赛,共12个人参加,比赛两轮,第一轮为淘汰赛 第二轮为决赛 4 每名选手都有对应的编号:如10001~10012 5 比赛方式:分组比赛 每组6人 6 第 ...
- STL函数 lower_bound 和 upper_bound 在算法竞赛中的用法
以前比较排斥这两个函数,遇到需要二分的情景都是手写 \(while(left<=right)\). 这次决定洗心革面记录一下这两个函数的在算法竞赛中的用法,毕竟一般不会导致TLE. 其实百度百科 ...
- java:比赛中常用方法整理——字符串(基础)
一.将字符串转化为字符数组: toCharArray返回一个字符数组. char[] a=J.toCharArray(); 二.字符串的长度 字符串的长度和字符数组的长度是不一'样'的. 字符串长度( ...
- C++复习:STL之算法
算法 1算法基础 1.1算法概述 算法部分主要由头文件<algorithm>,<numeric>和<functional>组成. <algorithm> ...
- [阿里移动推荐算法]比赛_快速入门_4_19_update_仅供参考,思维不要受局限
[这里只讲快速入门——即破题,正负样本不平衡.特征数量等问题就自己多看论文或者其他资料吧~~如果还有数据挖掘相关基础知识不了解的,建议看看<数据挖掘导论>] [以下是理解错误案例]:错误的 ...
- 常用的STL查找算法
常用的STL查找算法 <effective STL>中有句忠告,尽量用算法替代手写循环:查找少不了循环遍历,在这里总结下常用的STL查找算法: 查找有三种,即点线面: 点就是查找目标为单个 ...
- 【STL】帮你复习STL泛型算法 一
STL泛型算法 #include <iostream> #include <vector> #include <algorithm> #include <it ...
随机推荐
- 2018软工实践—Alpha冲刺(8)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ...
- 2018软工实践—Alpha冲刺(2)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前端界面的开发 搭建测试用服务器的环境 完成 ...
- 软工 · 第十一次作业 - Alpha 事后诸葛亮(团队)
软工 · 第十一次作业 - Alpha 事后诸葛亮(团队) 组长本次作业链接 现代软件工程 项目Postmortem 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场 ...
- jQuery之基本选择器
1. 是什么? - 有特定格式的字符串2. 作用 - 用来查找特定页面元素3. 基本选择器 - #id : id选择器 - element : 元素选择器 - .class : 属性选择器 - * : ...
- javascript之容易出错的地方
1: 不是所有的非空对象都有toString()方法的 var obj = Object.create(null); console.log(obj.toString()); // false; ...
- Spring Boot 学习资料【m了以后看】(转)
推荐博客: 程序员DD SpringBoot集成 liaokailin的专栏 纯洁的微笑 SpringBoot揭秘与实战 catoop的专栏 方志朋Spring Boot 专栏 简书Spring Bo ...
- 虚拟机中安装 centOS,本地安装 SSH 连接 - 01
下面把自己安装 centOS 的过程记录下,选取的版本是 centOS6.8 ,下载地址在脚本之家 down 的 : 阿里云 x64 http://mirrors.aliyun.com/centos/ ...
- Delphi下使用指针的简单总结
由于最近公司太忙,好久没有更新我的BLOG了.原来想着写写关于HOOK驱动的文章,可是最后想想好久已经没有做驱动的东西了,怕写出来有错误,于是作罢.开发游戏也有一段时间了,发现使用DELPHI来开发网 ...
- C# 为VB6.0程序模拟串口数据
为VB6.0编写程序模拟数据测试使用. 一.VB6.0 控件MSComm,来发送接收串口数据 CommPort 属性设置并返回通讯端口号,虚拟端口为COM2. Settings 属性设置并返回端口的波 ...
- solr源码分析之solrclound
一.简介 SolrCloud是Solr4.0版本以后基于Solr和Zookeeper的分布式搜索方案.SolrCloud是Solr的基于Zookeeper一种部署方式.Solr可以以多种方式部署,例如 ...