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

  1. 全排列问题

  #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();
}
  1. 往年蓝桥杯中用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();
}

课后习题:

  1. 问题二(会用到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 混合牛奶

http://codevs.cn/problem/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在算法比赛中简单应用的更多相关文章

  1. LintCode2016年8月8日算法比赛----中序遍历和后序遍历构造二叉树

    中序遍历和后序遍历构造二叉树 题目描述 根据中序遍历和后序遍历构造二叉树 注意事项 你可以假设树中不存在相同数值的节点 样例 给出树的中序遍历: [1,2,3] 和后序遍历: [1,3,2] 返回如下 ...

  2. STL 统计vector容器中指定对象元素出现的次数:count()与count_if()算法

    1 统计vector向量中指定元素出现的次数:count()算法 利用STL通用算法统计vector向量中某个元素出现的次数:count()算法统计等于某个值的对象的个数. #include &quo ...

  3. C++ 基于STL的演讲比赛流程管理系统(sort算法+小型算法(accumulate)+内建函数对象+string字符串拼接+字符串截取+多个容器基础操作+与用户交互+文件的读写+保存+重建+整体文件数据的清空)

    1 /* 2 比赛规则: 3 学校举行一演讲比赛,共12个人参加,比赛两轮,第一轮为淘汰赛 第二轮为决赛 4 每名选手都有对应的编号:如10001~10012 5 比赛方式:分组比赛 每组6人 6 第 ...

  4. STL函数 lower_bound 和 upper_bound 在算法竞赛中的用法

    以前比较排斥这两个函数,遇到需要二分的情景都是手写 \(while(left<=right)\). 这次决定洗心革面记录一下这两个函数的在算法竞赛中的用法,毕竟一般不会导致TLE. 其实百度百科 ...

  5. java:比赛中常用方法整理——字符串(基础)

    一.将字符串转化为字符数组: toCharArray返回一个字符数组. char[] a=J.toCharArray(); 二.字符串的长度 字符串的长度和字符数组的长度是不一'样'的. 字符串长度( ...

  6. C++复习:STL之算法

    算法 1算法基础 1.1算法概述 算法部分主要由头文件<algorithm>,<numeric>和<functional>组成. <algorithm> ...

  7. [阿里移动推荐算法]比赛_快速入门_4_19_update_仅供参考,思维不要受局限

    [这里只讲快速入门——即破题,正负样本不平衡.特征数量等问题就自己多看论文或者其他资料吧~~如果还有数据挖掘相关基础知识不了解的,建议看看<数据挖掘导论>] [以下是理解错误案例]:错误的 ...

  8. 常用的STL查找算法

    常用的STL查找算法 <effective STL>中有句忠告,尽量用算法替代手写循环:查找少不了循环遍历,在这里总结下常用的STL查找算法: 查找有三种,即点线面: 点就是查找目标为单个 ...

  9. 【STL】帮你复习STL泛型算法 一

    STL泛型算法 #include <iostream> #include <vector> #include <algorithm> #include <it ...

随机推荐

  1. 2018软工实践—Alpha冲刺(8)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ...

  2. 2018软工实践—Alpha冲刺(2)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前端界面的开发 搭建测试用服务器的环境 完成 ...

  3. 软工 · 第十一次作业 - Alpha 事后诸葛亮(团队)

    软工 · 第十一次作业 - Alpha 事后诸葛亮(团队) 组长本次作业链接 现代软件工程 项目Postmortem 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场 ...

  4. jQuery之基本选择器

    1. 是什么? - 有特定格式的字符串2. 作用 - 用来查找特定页面元素3. 基本选择器 - #id : id选择器 - element : 元素选择器 - .class : 属性选择器 - * : ...

  5. javascript之容易出错的地方

    1: 不是所有的非空对象都有toString()方法的 var obj = Object.create(null); console.log(obj.toString());   // false; ...

  6. Spring Boot 学习资料【m了以后看】(转)

    推荐博客: 程序员DD SpringBoot集成 liaokailin的专栏 纯洁的微笑 SpringBoot揭秘与实战 catoop的专栏 方志朋Spring Boot 专栏 简书Spring Bo ...

  7. 虚拟机中安装 centOS,本地安装 SSH 连接 - 01

    下面把自己安装 centOS 的过程记录下,选取的版本是 centOS6.8 ,下载地址在脚本之家 down 的 : 阿里云 x64 http://mirrors.aliyun.com/centos/ ...

  8. Delphi下使用指针的简单总结

    由于最近公司太忙,好久没有更新我的BLOG了.原来想着写写关于HOOK驱动的文章,可是最后想想好久已经没有做驱动的东西了,怕写出来有错误,于是作罢.开发游戏也有一段时间了,发现使用DELPHI来开发网 ...

  9. C# 为VB6.0程序模拟串口数据

    为VB6.0编写程序模拟数据测试使用. 一.VB6.0 控件MSComm,来发送接收串口数据 CommPort 属性设置并返回通讯端口号,虚拟端口为COM2. Settings 属性设置并返回端口的波 ...

  10. solr源码分析之solrclound

    一.简介 SolrCloud是Solr4.0版本以后基于Solr和Zookeeper的分布式搜索方案.SolrCloud是Solr的基于Zookeeper一种部署方式.Solr可以以多种方式部署,例如 ...