第五章 C++与STL入门
5.1 C++
#104 问题:输入数据的每行包含若干个(至少一个)以空格隔开的整数,输出每行中所有整数之和。
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main(){
string line;
while(getline(cin,line)){
int sum = 0,x;
stringstream ss(line);
while(ss >> x){
sum += x;
}
cout << sum << "/n";
}
return 0;
}
stringstream 在头文件 sstream 中,sstream 定义了三个类 istringstream 、 ostringstream 和 stringstream 分别用于流的输入、输出和操作。主要用于数据类型的转换:转为string类型。
#105 虽然 string 和 stream 都很方便,但 string 很慢, sstream 更慢。
5.2 STL
- #108 UVa.10474 Where is the Marble?
N个大理石,每个大理石上写了一个非负整数。首先把各数从小到大排序,然后回答Q个问题。每个问题问是否有一个大理石写着某个整数x,如果是,还要回答哪个大理石上写着x。排序后的大理石从左到右编号为1~N。
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 10000;
int main(){
int n,q,x,a[maxn],Case=0;
while(scanf("%d%d",&n,&q) == 2 && n){
printf("CASE# %d:\n", ++Case);
for(int i = 0;i < n;i++){
cin >> a[i];
}
sort(a,a+n);
while(q--){
cin >> x;
int p = lower_bound(a,a+n,x) - a;
if(a[p] == x)
cout << x << " found at " << p+1 <<endl;
else
cout << x <<" not found" <<endl;
}
}
return 0;
}
第一遍错误解答,检查好一会发现没有加endl
。
注意到,在UVa10474中:
scanf("%d%d",&n,&q) == 2 && n
:==2
左式有n个未知量就==n,判断n个未知量输入是否符合标准。&& n
判断n不为0。
sort(a,a+n)
:从小到大排普通数组。sort(a.begin(),a.end())
:从小到大排vector。
lower_bound(a,a+n,x)
:查找“大于或者等于x的第一个位置”。
- #110 UVa.101 The Blocks Problem
从左到右n个木块,编号为0~n-1,要求模拟以下4种操作:
• move a onto b: 将 a 和 b 归位,把 a 放在 b 上
• move a over b: 将 a 归位, a 放在 b 的顶部
• pile a onto b: 将 b 归位, a 及上面木块整体摞在 b 上
• pile a over b: 将 a 及上面木块整体摞在 b 顶
• quit: 终止
a 和 b 在同一堆时是非法指令,忽略。
所有操作结束后,输出每个位置的木块列表,按照从底到顶的顺序排列。
观察到,有且只有 onto 操作对 b 归位,move 操作对 a 归位。
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cstdio>
using namespace std;
const int maxn = 30;
vector<int> pile[maxn];
int n;
void find(int a,int& p,int& h){
for(p=0;p<n;p++){ //wrong2
for(h=0;h<pile[p].size();h++){
if(pile[p][h]==a)
return;
}
}
}
void back(int p,int h){
for(int i=h+1;i<pile[p].size();i++){
int b=pile[p][i];
pile[b].push_back(b);
}
pile[p].resize(h+1);
}
void pile_over(int a,int p,int h){
for(int i=h;i<pile[p].size();i++){
int b=pile[p][i];
pile[a].push_back(b);
}
pile[p].resize(h);
}
int main(){
cin>>n;
string s1,s2;
int a,b;
for(int i=0;i<n;i++){ //initialization
pile[i].push_back(i);
}
while(cin>>s1>>a>>s2>>b){
int pa,pb,ha,hb;
find(a,pa,ha);
find(b,pb,hb);
if(pa == pb) continue;
if(s1 == "move") back(pa,ha);
if(s2 == "onto") back(pb,hb);
pile_over(pb,pa,ha); //wrong1
}
for(int i=0;i<n;i++){ //print
cout<<i<<":";
for(int j=0;j<pile[i].size();j++){
cout<<" "<<pile[i][j];
}
cout<<endl;
}
return 0;
}
#112 vector是一个不定长数组
wrong1:pile_over(pb,pa,ha);
中的 pb 写成 b。
wrong2:循环中在已经定义过的变量前又加了一次 int 。
注意到,头文件#include<cstdio>
不必要。
万能头文件 #include<bits/stdc++.h>
- #112 UVa.10815 Andy’s First Dictionary
输入一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出。单词不区分大小写。
#include<bits/stdc++.h>
using namespace std;
set<string> dict;
int main(){
string x,temp;
while(cin>>x){
for(int i = 0;i < x.length();i++){
if(isalpha(x[i])){
x[i] = tolower(x[i]);
}
else{
x[i] = ' ';
}
}
stringstream ss(x);
while(ss >> temp){
dict.insert(temp);
}
}
for(set<string>::iterator it = dict.begin();it != dict.end();it++){
cout<<*it<<endl;
}
return 0;
}
#113 set 中元素已从小到大排好序,用一个for即可从小到大遍历其中所有元素,set<string>::iterator
迭代器,类似于指针。
- #113 UVa.156 Ananagrams
输入一些单词,找到满足条件的单词:该单词不能通过字母重排得到输入文本中的另外一个单词。判断时不区分大小写。输出时保留大小写,按字典序排列(所有大写排在小写前面)。输入 “#” 结束。
#include<bits/stdc++.h>
using namespace std;
string stan(string s){
for(int i = 0;i < s.size();i++){
s[i] = tolower(s[i]);
}
sort(s.begin(),s.end());
return s;
}
int main(){
vector<string> words;
map<string,int> cnt;
string s;
while(cin >> s){
if(s[0] == '#') break;
words.push_back(s);
string t = stan(s);
if(!cnt.count(t)) cnt[t] = 0;
cnt[t]++;
}
vector<string> ans;
for(int i = 0 ; i < words.size() ; i++){
if(cnt[stan(words[i])] == 1){
ans.push_back(words[i]);
}
}
sort(ans.begin(),ans.end());
for(int i = 0;i < ans.size();i++){
cout << ans[i] << endl;
}
return 0;
}
#115 STL 的栈定义在头文件 < stark > 中,用 stark<T> s
方式声明栈。操作有 push pop top。
- #115 UVa.12096 The SetStack Computer
设计“集合栈”计算机,包括操作:
PUSH:空集合入栈。
DUP:当前栈顶元素复制一份后入栈。
UNION:出栈两个集合,把二者并集入栈。
INTRESECT:出栈两个集合,把二者交集入栈。
ADD:出栈两个集合,把先出栈的集合加入到后出栈的集合中,把结果入栈。
每次操作后,输出栈顶集合的大小。
#include<bits/stdc++.h>
using namespace std;
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
typedef set<int> Set;
map<Set,int> IDcache;
vector<Set> Setcache;
int ID (Set x){ //查找给定集合x的ID。找不到则分配新ID。
if(IDcache.count(x)){
return IDcache[x];
}
Setcache.push_back(x);
return IDcache[x] = Setcache.size() - 1;
}
int main(){
stack<int> s;
int t,n;
cin>>t;
while(t--){
cin>>n;
for(int i = 0;i < n;i ++){
string op;
cin>>op;
if(op[0] == 'P') s.push(ID(Set())); //空集入栈
else if(op[0] == 'D') s.push(s.top());
else{
Set x1 = Setcache[s.top()]; s.pop();
Set x2 = Setcache[s.top()]; s.pop();
Set x;
if(op[0] == 'U') set_union (ALL(x1),ALL(x2),INS(x));
if(op[0] == 'I') set_intersection (ALL(x1),ALL(x2),INS(x));
if(op[0] == 'A'){
x = x2;
x.insert(ID(x1));
}
s.push(ID(x));
}
cout << Setcache[s.top()].size() << endl;
}
cout << "***" << endl;
}
return 0;
}
#116 为每个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合,这样就可以用STL的 set<int>
来表示,而整个栈则是一个 stack<int>
。
对任意集合 s (类型为自定义的 Set ),IDcache[s] 是它的 ID ,而 Setcache[IDcache] 是 s 本身。 ALL 和 INS 是两个宏,分别表示“所有的内容”以及“插入迭代器”。
set_union(A.begin() , A.end() , B.begin() , B.end() , inserter(C1, C1.begin()) )
。将集合A、B取并集后的结果存入集合C中。set_union(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator<T>(cout," “));
将A、B取并集后的结果直接输出,(cout," ")双引号里是输出用来间隔集合元素的符号或是空格。
set 中有 set_intersection
(取集合交集)、set_union
(取集合并集)、set_difference
(取集合差集)、set_symmetric_difference
(取集合对称差集)等函数。
不难看出,这里的宏就是替代了括号中的部分。