1 - P1996 约瑟夫问题
题目大意
共n个人,每次数到第m个人时,这个人则会出圈,出圈后会再次从1开始数数,直至所有人都出圈,要求按顺序输出出圈人的编号
解题思路
可以想到队列,先进行计数是第几个人,在未到第m个人时先读入再弹出,直至到第m个人输出第m个人的编号,再次从头开始计数,如此循环
坑点
无
代码
#include<iostream>
using namespace std;
#include<queue>//队列所需头文件
queue<int>q;//读入的数,int类型
int n,m,bs=1;//n人,m时出圈,bs报数
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
q.push(i);//先把数放入队列中
}
while(!q.empty())//队列非空时
{
if(bs==m)//报数等于m需出圈
{
cout<<q.front()<<" ";//先输出
q.pop();//再弹出
bs=1;//重新计数
}
else//报数未到 m 时
{
bs++;//报数++
q.push(q.front());//将队首放入
q.pop();//弹出
}
}
return 0;
}
总结
需要熟练掌握 queue 的用法和具体在题中如何操作
2 - P1540 [NOIP2010 提高组] 机器翻译
题目链接
题目大意
n个单词,m个内存量,每当内存内存单词数>=m时,会将最初存入的进行弹出,下一个单词继续存入,如此反复,问需要查词典的次数
解题思路
要弹出最初存入的单词,那么可以想到队列,每次将front 位置的单词进行弹出,和判断单词是否在内存中
坑点
无
代码
#include<iostream>
#include<queue>
using namespace std;
int m,n,ans;
queue<int>q;//模拟存单次的情况
bool f[1010];//判断单词是否在内存中
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
if(f[x]!=0)
{
continue;//能够在内存中找到就 不需查字典
}
else//不能在内存中找到
{
if(q.size()>=m)//当内存的数量>=m时
{
f[q.front()]=false;//将第一次存入的变为 变为相反状态
q.pop();//并弹出
}
//不在内存内的
q.push(x);//先存入内存
f[x]=true;//对应状态变为 true
ans++;//查单词次数++
}
}
cout<<ans;//输出总的查单词的数量
return 0;
}
总结
需能想到还需对单词是否在内存内的状态进行判断,将题目分析透彻会好做些
3 - P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
题目大意
给你n种果子,和每种的数量,每两种可以合并成一堆,问最终全部合并成一堆最少需要消耗多少体力值
解题思路
题目中有提到堆,那么想到 优先队列,要求最小体力消耗值,那么要用到小顶堆,再将两个队头进行相加
坑点
无
代码
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int ,vector<int>,greater<int> >q;//从小到大进行排序,是小顶堆
int n,x,ans;
int main()
{
cin>>n;//n种果子
for(int i=1;i<=n;i++)
{
cin>>x;//依次读入n种果子 的数量
q.push(x);//放入优先队列中
}
while(q.size()>=2)//当优先队列中有>=2中2果子时
{
int a=q.top();//把 队头 赋给 a
q.pop();//弹出
int b=q.top();//再把队头赋给 b
q.pop();//再次弹出
q.push(a+b);//再将 a+b存入队列中
ans+=a+b;//体力消耗值 += 合并的数量和
}
cout<<ans;//输出最小体力消耗值
return 0;
}
总结
需思考清楚用哪个堆的时候使体力消耗值最小
4 - P1165 日志分析
题目大意
n次操作,给出操作的三种格式,要求按照操作输出具体的重量,为空时则输出0
解题思路
根据题意,先进后出则可以想到栈,格式三时,要输出最重的重量
坑点
无
代码
#include<iostream>
#include<stack>
using namespace std;
stack<int >a;
stack <int>b;
int n,op,x;
int main()
{
cin>>n;//n次操作
while(n--)
{
cin>>op;//依次读入操作看是第几种
if(op==0)//如果是 格式一 0 X
{
cin>>x;//读入
if(b.empty()||x>b.top())//当b栈为空 或者 读入的x是否比栈顶要大
{
b.push(x);//插入b栈中
}
else//相反
{
b.push(b.top());//将栈顶插入b中
}
}
else if(op==1)//操作为格式二 1
{
//a.pop();
b.pop();//需将栈顶进行弹出
}
else if(op==2)//操作为格式三时 2
{
if(b.empty())//如果此时b栈为空 那么
{
cout<<"0\n";//输出 0
}
else//非空
{
cout<<b.top()<<endl;//输出栈顶
}
}
}
return 0;
}
总结
需熟练掌握的stack的操作
5 - P1739 表达式括号匹配
题目大意
给你一个表达式,问在结束符‘@’之前,左右括号是否匹配
解题思路
可以选择使用字符串或者是字符进行读入,然后判断左右括号的是否匹配
坑点
并不是单纯左右括号的数量是否相等,还需判断谁前谁后,必须是左括号在前右括号在后,并且数量相等的情况下,才算匹配
代码
做法一
#include<iostream>
using namespace std;
int main()
{
char c;
int zuo=0,you=0;
do{
cin>>c;//读入字符
if(c=='(')//是左括号时
{
zuo++;//左括号数量++
}
if(c==')')//是右括号时
{
you++;//右括号数量++
}
if(you>zuo)//只要中间出现右括号数量>左括号数量
{
cout<<"NO";//不符合情况
return 0;//停止
}
}
while(c!='@');//在结束符号之前
{
if(zuo==you)//左括号数量等于右括号数量
{
cout<<"YES"; //符合情况 YES
}
else
{
cout<<"NO";//不符合则输出NO
}
}
return 0;
}
做法二
#include<iostream>
#include<cstring>
using namespace std;
int a=0,b=0;
string s;
int main()
{
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')
{
a++;
}
else if(s[i]==')')
{
b++;
}
if(b>a)
{
cout<<"NO";
return 0;
}
}
if(a==b)
{
cout<<"YES";
}
else {
cout<<"NO";
}
return 0;
}
总结
难度简单,要读清楚题意