STL经典列题练习
课上练习stack
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(1){
cout << "10进制:";
cin >> n;
if(n==-1) break;
stack<int> st;
while(n){
int a=n%8;
n/=8;
st.push(a);
}
cout << "8进制:";
while(!st.empty()){
cout << st.top();
st.pop();
}
cout << endl;
}
return 0;
}
括号匹配
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin >> s;
stack<char> st;
int f=1;
for(int i=0;i<s.size();i++){
if(s[i]=='('||s[i]=='[') st.push(s[i]);
else{
if(st.empty()) f=0;
else if((s[i]==')'&&st.top()!='(')||(s[i]==']'&&st.top()!='[')) f=0;
else if((s[i]==')'&&st.top()=='(')||(s[i]==']'&&st.top()=='[')){
st.pop();
}
}
}
if(!st.empty()) f=0;
cout << f << endl;
return 0;
}
F - 士兵队列训练问题 HDU - 1276
vector模拟问题
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
vector<int> v;
int n;
cin >> n;
for(int i=1;i<=n;i++) v.push_back(i);
int add=1;
while(v.size()>3){
if(add==1){
for(int i=1;i<v.size();i++){
v.erase(v.begin()+i,v.begin()+i+1);
}
add=2;
}
else{
for(int i=2;i<v.size();i+=2){
v.erase(v.begin()+i,v.begin()+i+1);
}
add=1;
}
}
for(int i=0;i<v.size();i++){
if(!i) cout << v[i];
else cout << ' ' << v[i];
}
cout << endl;
}
return 0;
}
G - 产生冠军 HDU - 2094
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin >> n&&n){
set<string> s1,s2;
string a,b;
while(n--){
cin >> a >> b;
s1.insert(a);
s1.insert(b);
s2.insert(b);
}
if(s1.size()-s2.size()==1) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
/*
这题用set就特别简单,set1表示所有人的集合,set2表示所有失败者的集合,那只要set1比set2大1就表示有一人是胜利者;
*/
vjudge地址
第一题:A - Shopping HDU - 2648
题目大意:求memory店每天的排名
分析:map题目
重点:map和迭代器的使用
易错:多组输入
#include<bits/stdc++.h>
using namespace std;
int main(){//注意多组数据输入
int n;
while(cin >> n){
map<string,int> shop;//运用map ,一种映射
map<string,int>::iterator it;//迭代器
for(int i=1;i<=n;i++){
string s;
cin >> s;
shop[s]=0;//可有可无,默认是0
}
int day;
cin >> day;
while(day--){
int a;
string s;
for(int i=1;i<=n;i++){
cin >> a >> s;
shop[s]+=a;//在迭代器中加入增加的值
}
//开始运用迭代器循环找出memory第几名
int rank=1;//记录排名
for(it=shop.begin();it!=shop.end();it++){
if(it->second>shop["memory"]) rank++;
}
cout << rank << endl;
}
}
return 0;
}
B - Ignatius and the Princess II HDU - 1027
next_permutation()函数
分析:可以用dfs做,会有点麻烦,在stl中有个更简单的函数,next_permutation
#include<iostream>//全排列多种办法
#include<algorithm>
using namespace std;
int a[1005];
int main(){
int n,m;
while(cin >> n >> m){
for(int i=1;i<=n;i++) a[i]=i;
int b=1;
do{
if(b==m) break;
b++;
}while(next_permutation(a+1,a+n+1));//模板
for(int i=1;i<=n;i++){
if(i==1) cout << a[i];
else cout << ' ' <<a[i];
}
cout << '\n';
}
return 0;
}
C - 排列2 HDU - 1716
这一题一看就和B题很相似,首先理解next_permutation能实现什么样的功能,首先得对数组排序,返回存在的下一个排序
代码
易错:就是题目里给你空行,不注意容易出现Presentation Error的错误
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
int a[4],ok=0;
cin>>a[0]>>a[1]>>a[2]>>a[3];
while(1){
if(a[0]+a[1]+a[2]+a[3]==0) break;
sort(a,a+4);//排序
int k=a[0];
if(a[0]!=0) cout<<a[0]<<a[1]<<a[2]<<a[3];
while(next_permutation(a,a+4)){
if(a[0]==k&&a[0]!=0) cout<<" "<<a[0]<<a[1]<<a[2]<<a[3];
else{
if(a[0]!=0){
if(k!=0) cout<<endl;//换行
cout<<a[0]<<a[1]<<a[2]<<a[3];
}
k=a[0];
}
}
cout<<endl;
cin>>a[0]>>a[1]>>a[2]>>a[3];//仅仅有下次不退出才换行
if(a[0]+a[1]+a[2]+a[3]!=0) cout<<endl;
}
return 0;
}
D - Where is the Marble? UVA - 10474
题目大意:输入n个整数,代表大理石编号;再输入q个数(编号),问是否有这个编号的大理石,位置在哪里?
了解 lowwer_bound()与upper_bound()
#include<bits/stdc++.h>
using namespace std;
int cnt[100000];
int main(){
int n,m,count=1;//标记case
while(cin >> n >> m){
if(!n&&!m) break;
printf("CASE# %d:\n",count++);
for(int i=1;i<=n;i++) cin >> cnt[i];
sort(cnt+1,cnt+n+1);//关键排序
while(m--){
int a;
cin >> a;
int b=lower_bound(cnt+1,cnt+n+1,a)-cnt;//lowwer_bound的使用
if(cnt[b]==a) printf("%d found at %d\n",a,b);
else printf("%d not found\n",a);
}
}
return 0;
}
E - The Blocks Problem UVA - 101
题目大意: 先理解给出的四个移动方式:
move a onto b:把木块a、b上的木块放回各自的原位,再把a放到b上;
move a over b:把a上的木块放回各自的原位,再把a发到含b的堆上;
pile a onto b:把b上的木块放回各自的原位,再把a连同a上的木块移到b上;
pile a over b:把a连同a上木块移到含b的堆上。
然后根据条件来移动即可。
解题思路
如果把每个情况都写出来肯定很麻烦,所以首先先找出他们的共同点然后来写出算法,这样就会简单很多,如
找到某木块
将某木块上的木块放回原位
将某木块及其上面木块移动到另一个木块上
vector 模拟题
#include<string>
#include<vector>
#include<iostream>
using namespace std;
int n;
vector<int> num[24];
void find(int a, int & i, int &j )
{
for (i = 0; i < n; i++)
for (j = 0; j< num[i].size(); j++)
if (num[i][j] == a) return;
}
void over(int j, int h)
{
for (int i = h + 1; i < num[j].size(); i++)
{
int b = num[j][i];
num[b].push_back(b);
}
num[j].resize(h + 1);
}
void renew(int p, int h, int g )
{
for (int i = h; i < num[p].size(); i++)
num[g].push_back(num[p][i]);
num[p].resize(h);
}
int main()
{
int a, b;
cin >> n;
string s1, s2;
for (int i = 0; i < n; i++)
num[i].push_back(i);
while (cin >> s1)
{
if (s1 == "quit")
{
for (int i = 0; i < n; i++)
{
cout << i<<":";
for (int j = 0; j < num[i].size(); j++)
cout <<" "<<num[i][j];
cout << endl;
}
break;
}
cin >> a >> s2 >> b;
int q, w, e, r;
find(a, q, e);
find(b, w, r);
if (q == w)
continue;
if (s2 == "onto")
over(w, r);
if (s1 == "move")
over(q, e);
renew(q, e, w);
}
system("pause");
return 0;
}
F - Andy’s First Dictionary UVA - 10815
题意:
给你一段文字,把所有的单词挑出来,然后转小写排序打印、
打印的时候不能打印重复的,因此,在打印的时候一个判断就好‘
解析
集合set的用法 :
1.set是数学上的一个集合,每个元素最多只出现一次,使得省略去重操作。
2.由于string已经定义了“小于”符号,使得存入set中的元素已经从小到大排好序
,所以直接用set保存单词集合。
tolower()函数
#include<bits/stdc++.h>
using namespace std;
int main(){
set<string> se;
set<string>::iterator it;
string s;
while(cin >> s){//输入字符串
int pos=0,len=s.size();
while(1){//知道EOF结束
string ss;
while(isalpha(s[pos])){//取出一个完整的字符串
ss+=s[pos];
pos++;
}
for(int i=0;i<ss.size();i++) ss[i]=tolower(ss[i]);//转小写
if(ss!="") se.insert(ss);//如果ss有值,便存入set
if(pos>=len) break;
pos++;
}
}
for(it=se.begin();it!=se.end();it++){//迭代器输出
cout << *it << endl;
}
return 0;
}
数据流写法更简便,原理相同,数据流取出单词方式不同
#include<set>
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
set<string> dict; //string 集合
int main()
{
string s,buf;
while(cin>>s)
{
for(int i=0;i<s.length();i++)
{
if(isalpha(s[i]))
s[i]=tolower(s[i]);
//tolower将大写字母转为小写
else s[i]=' ';
}
stringstream ss(s);
while(ss>>buf)
dict.insert(buf);
}
for(set<string>::iterator it=dict.begin();it!=dict.end();it++)
cout<<*it<<endl;
return 0;
}
G - Ananagrams UVA - 156
对比给出的字符串是否存在无论怎么变换字母位置都不会重复的字符串,将他按字典序输出
思路:先把单词从字符串中提取出来存入vector中,然后复制一份把大写改为小写,并且对每个单词内字母排序,然后对比vector里面的单词看出现的次数,看是不是只出现一次还是出现多次。。
#include<bits/stdc++.h>
using namespace std;
map<string,int> m;
map<string,int>::iterator it;
bool cmp1(string s1,string s2){//对字符串数组排序
return s1<s2;
}
bool cmp2(char x,char y){//对字符串排序
return x<y;
}
string tran(string s){//将字符串转化为排完序的字符串
for(int i=0;i<s.size();i++){
s[i]=tolower(s[i]);
}
sort(s.begin(),s.end(),cmp2);
return s;
}
int main(){
string s;
vector<string> v;//储存原字符
while(cin >> s){
if(s=="#") break;
v.push_back(s);
string ss=tran(s);
m[ss]++;
// cout << ss << endl;
}
sort(v.begin(),v.end(),cmp1);排序
for(int i=0;i<v.size();i++){
if(m[tran(v[i])]==1) cout << v[i] << endl;
}
return 0;
}
H - The SetStack Computer UVA - 12096
难,我也不会,尽力了
I - Team Queue UVA - 540
题解:题意就是一个队列相同组的可以插队,插到相同队员的后面,思路是弄多个队列,用一个队列来确定队编号的序列,一个数组判断当前队是否还有队员,没有队员标记为空;
他人解说
J - Ugly Numbers UVA - 136
题目大意:丑数是指不能被2,3,5以外的其他素数整除的数。求第1500个丑数。
思路:最小的丑数是1,对任意丑数x,2x,3x,5x也是丑数。用优先 队列保存已经生成的丑数,再依次取出最小的丑数生成三个新的丑数就好了,注意生成丑数的来源多种,需要判断新生成的丑数是否已存在。
需要用到set来去重,也需要用到优先队列去将思路中新生成的丑数排序。
题目解析
优先队列解析
#include<iostream>
#include<vector>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int coeff[3] = { 2, 3, 5 };
int main()
{
priority_queue <ll,vector<ll>,greater<ll> > pq;//自定义排序,默认是从大到小
set<ll>s;
pq.push(1);
s.insert(1);
for (int i = 1;; i++)
{
ll x = pq.top(); pq.pop();
if (i == 1500)
{
cout << "The 1500'th ugly number is " << x << "." << endl;
break;
}
for (int j = 0; j < 3; j++)
{
ll x2 = x*coeff[j];
if (!s.count(x2))
{
s.insert(x2);
pq.push(x2);
}
}
}
return 0;
}
L - 单词数 HDU - 2072
思路:set去重
输入方法新思路,运用stringstream,可以直接将带空格的字符串隔开,并一一输出剩余的字符串!
Stringstream运用
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
set<string> se;
set<string>::iterator it;
while(getline(cin,s)&&s!="#"){
stringstream ss;
ss<<s;
string p;
while(ss>>p){
se.insert(p);
}
cout << se.size() << endl;
se.clear();
}
/*
for(it=se.begin();it!=se.end();it++){
cout << *it << endl;
}
*/
return 0;
}