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. 线段树---成段更新hdu1698 Just a Hook

    hdu1698 Just a Hook 题意:O(-1) 思路:O(-1) 线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息) 题意:给一组棍子染色,不同 ...

  2. NULL指针引起的一个linux内核漏洞

    NULL指针一般都是应用于有效性检测的,其实这里面有一个约定俗成的规则,就是说无效指针并不一定是 NULL,只是为了简单起见,规则约定只要指针无效了就将之设置为NULL,结果就是NULL这个指针被用来 ...

  3. 0302思考&回答

    看完这两个网页,我们可以看出it行业始终是一门热门行业,在现在这个人潮汹涌的人才市场,面对严峻的就业形势,我们应该拿什么去参见招聘?人多而工作职位有限,这警醒我们必须拥有一技之长,否则则会被淘汰.如果 ...

  4. psp 第二周

    11号                                                                              12号 类别c 内容c 开始时间s 结 ...

  5. ci事务

    CI框架百问百答:CodeIgniter的事务用法?--第9问 时间 2013-06-06 10:57:45  CSDN博客 原文  http://blog.csdn.net/haor2756/art ...

  6. java 基础 --Collection(Map)

    Map是不是集合?哈哈哈 java编程思想>的第11章,第216页,正数第13行,中原文:“……其中基本的类型是LIst.Set.Queue和Map.这些对象类型也称为集合类,但由于Java类库 ...

  7. perf的采样模式和统计模式

    perf的采样模式和统计模式 统计模式和采样模式使用寄存器的方法不相同; 在统计模式下,每次调度之前设置寄存器,调度之后清理寄存器,留个下个进程使用;PMU寄存器的使用方法; 在采样模式下,每次 pm ...

  8. 解决sublime install package连不上的问题

    下载文件 百度网盘:https://pan.baidu.com/s/1Z-11d4btZJyx5zA7uzNi8Q 修改配置文件 转载请注明博客出处:http://www.cnblogs.com/cj ...

  9. 【明哥报错簿】tomcat 安装时出现 Failed to install Tomcat7 service

    安装tomcat时提示 Failed to install Tomcat7 service 应该是卸载时直接删除目录导致的. Failed to install Tomcat7 service Che ...

  10. Howto run google-chrome as root

    Just want to add a permanent solution to the problem: 1. Open google-chrome located in /usr/bin with ...