2022年暑假ACM专项训练之STL和基本数据结构(总结)

本文介绍了多种算法和数据结构的实际应用,包括圆桌问题的解决方案、字符串反转、优先级队列模拟、队列与栈的应用、寻找冠军策略、购物价格预测、排列问题以及 Ignatius 的数学挑战。通过这些实例,深入理解并掌握算法和数据结构在解决实际问题中的运用。
摘要由CSDN通过智能技术生成

A - 圆桌问题

圆桌上围坐着2n个人。其中n个人是好人,另外n个人是坏人。如果从第一个人开始数数,数到第m个人,则立即处死该人;然后从被处死的人之后开始数数,再将数到的第m个人处死……依此方法不断处死围坐在圆桌上的人。试问预先应如何安排这些好人与坏人的座位,能使得在处死n个人之后,圆桌上围坐的剩余的n个人全是好人。

Input

多组数据,每组数据输入:好人和坏人的人数n(<=32767)、步长m(<=32767);

Output

对于每一组数据,输出2n个大写字母,‘G’表示好人,‘B’表示坏人,50个字母为一行,不允许出现空白字符。相邻数据间留有一空行。

Sample

InputcopyOutputcopy
 
2 3
2 4
 
GBBG 
BGGB 

总结:使用vector可以节约时间。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
#include<vector>
using namespace std;

int main()
{ 
	vector<int>table;
	int n,m;
	
	while(cin>>n>>m)
	{ 
 	 
	 table.clear();//对每一次的vector进行清理,防止上一次数据的影响。
	 for(int i=0;i<2*n;i++)
		 table.push_back(i);
	int pose=0;
	 for(int i=0;i<n;i++)
	 {
	  pose=(pose+m-1)%table.size();//实现列表变成圆圈,下标超过总人数就从第一个开始。
	  table.erase(table.begin()+pose);//去掉元素。
	 
	 }
	
	 int j=0;
	 for(int i=0;i<2*n;i++)
	 {
	   if((i%50==0)&&i)//每50个为一行
		   cout<<endl;
	   if(i==table[j]&&j<table.size())//控制好人的人数及输出。
	   { 
	    cout<<"G";
		j++;
	   }
	   else
		   cout<<"B";
	 }
	 cout<<endl<<endl;
	 
	}
	
return 0;
}

B - Text Reverse

Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them.

Input

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single line with several words. There will be at most 1000 characters in a line.

Output

For each test case, you should output the text which is processed.

Sample

InputcopyOutputcopy
 
3 
olleh !dlrow 
m'I morf .udh 
I ekil .mca 
 
hello world! 
I'm from hdu. 
I like acm.

Hint


Remember to use getchar() to read '\n' after the interger T, then you may use gets() to read a line and process it.

总结:最好用getchar(),或者一行输入,cin通过不了,需要注意数字输入之后要吃掉一个空格,题目要求的,输出时要注意末尾不要有空格。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
int main()
{ 
int n;
string s;
while(cin>>n)
{ getchar();//吃掉数字后面的空格
  stack<char>table;
  char ch;
for(int i=0;i<n;i++){
  while(1)
  {
   ch=getchar();
    if(ch==' '||ch=='\n'||ch==EOF)//判断空格和换行、结束符
     {	
	   while(!table.empty())//全部输出
	   {
	     cout<<table.top();
	     table.pop();
	   }
	   if(ch=='\n'||ch==EOF)//如果是换行和结束符就退出循环,相当于处理下一行字符串
	   break;
	   cout<<" ";//不是换行和结束符就要输出一个空格
	 
	 
     }
	 else  
		table.push(ch);//不是空格和换行、结束符就入栈
		
		
  }
  cout<<endl;
}
}
return 0;
}

C - ACboy needs your help again!

ACboy was kidnapped!!
he miss his mother very much and is very scare now.You can't image how dark the room he was put into is, so poor :(.
As a smart ACMer, you want to get ACboy out of the monster's labyrinth.But when you arrive at the gate of the maze, the monste say :" I have heard that you are very clever, but if can't solve my problems, you will die with ACboy."
The problems of the monster is shown on the wall:
Each problem's first line is a integer N(the number of commands), and a word "FIFO" or "FILO".(you are very happy because you know "FIFO" stands for "First In First Out", and "FILO" means "First In Last Out").
and the following N lines, each line is "IN M" or "OUT", (M represent a integer).
and the answer of a problem is a passowrd of a door, so if you want to rescue ACboy, answer the problem carefully!

Input

The input contains multiple test cases.
The first line has one integer,represent the number oftest cases.
And the input of each subproblem are described above.

Output

For each command "OUT", you should output a integer depend on the word is "FIFO" or "FILO", or a word "None" if you don't have any integer.

Sample

InputcopyOutputcopy
 
4
4 FIFO
IN 1
IN 2
OUT
OUT
4 FILO
IN 1
IN 2
OUT
OUT
5 FIFO
IN 1
IN 2
OUT
OUT
OUT
5 FILO
IN 1
IN 2
OUT
IN 3
OUT
1
2
2
1
1
2
None
2
3

总结:实际上就是对queue和stack的应用,需要注意OUT后面不需要带数,IN后面需要带数字。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
int main()
{ 
 int n;
 int m;
  int t;
cin>>n;
while(n--)
{ 
string s1,f;
stack<int>s;
queue<int>q;
 
   cin>>m>>s1;
for(int w=0;w<m;w++)
{
   if(s1=="FIFO")//queue
   {  
	  cin>>f;
	  
	   if(f=="IN")//先判断是IN然后再输入一个数字
	    { cin>>t;q.push(t);}
	   if(f=="OUT")
	     {
		   if(q.empty())
		   cout<<"None"<<endl;

		else{
		 cout<<q.front()<<endl;//是OUT直接输出
	      q.pop();
	     }
	 }
	 
   
   }
   
   if(s1=="FILO")//stack
   {  
	  cin>>f;
	   if(f=="IN")
	      {cin>>t;s.push(t);}
	    if(f=="OUT")
	     {
		   if(s.empty())
		     cout<<"None"<<endl;
		else{
		 cout<<s.top()<<endl;
	      s.pop();}
	     }
	 
   
   }
   
}
 
 }



return 0;
}

D - 看病要排队

看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。

现在就请你帮助医院模拟这个看病过程。

Input

输入数据包含多组测试,请处理到文件结束。
每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。
接下来有N行分别表示发生的事件。
一共有两种事件:
1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10)
2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3)

Output

对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。

Sample

InputcopyOutputcopy
 
7
IN 1 1
IN 1 2
OUT 1
OUT 2
IN 2 1
OUT 2
OUT 1
2
IN 1 1
OUT 1
2
EMPTY
3
1
1

总结:采用priority_queue优先级队列,优先级的在前面,

 struct node{

 int priority;int index;

bool operator<(const node &b) const{

  if(priority==b.priority)

 return index>b.index;

return priority<b.priority;

}

};

#include<queue>
#include<string>
#include<stdio.h>
#include<iostream>
using namespace std;
struct node
{
 int priority;int index;
 bool operator<(const node &b)
 const{
  if(priority==b.priority)
     return index>b.index;//优先级相同,id值大的排后面
     
return priority<b.priority;//不同优先级,则小于
 
 
 }


};
int main()
{
   priority_queue<node>q[4];//大顶堆
   int n;
   while(cin>>n)
{
	
	for(int i=1;i<=3;i++)
	   while(q[i].size())
	     q[i].pop();
  string s;
  int a,b,t=1;
for(int i=0;i<n;i++)
{

  cin>>s;
  if(s=="IN")
  {
    cin>>a>>b;
    node temp;
    temp.priority=b;//优先级
    temp.index=t++;//id
    q[a].push(temp);//a医生入栈
  
  }
  if(s=="OUT")
  {
   cin>>a;
    if(q[a].size())
    {
	cout<<q[a].top().index<<endl;//输出a医生的病人id
	 q[a].pop();}
    
    else
    {
	  cout<<"EMPTY"<<endl;
	
	}
  }


}


}
    return 0;
}

E - 士兵队列训练问题

某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。

Input

本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。

Output

共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。

Sample

InputcopyOutputcopy
 
2
20
40
 
1 7 19
1 19 37

总结:采用list实现删除和插入。

#include<queue>
#include<string>
#include<stdio.h>
#include<iostream>
#include<list>
using namespace std;
int main()
{
  
  int n;
  while(cin>>n)
  {
  list<int>li;
  list<int>::iterator it;//迭代器
  for(int i=0;i<n;i++)
  {
  	li.clear();
   int m;
   cin>>m;
   for(int j=1;j<=m;j++)//初始化
      li.push_back(j);
    int k=2;
	while(li.size()>3) //判断元素的个数
  {  int num=1;
       for(it=li.begin();it!=li.end();)
          { if(num++%k==0)//每k个就删除一个
            {
		     it=li.erase(it);
		     }
		     else
		     it++;
			}  
			k==2?k=3:k=2;//设置k的值为2或者3
  }
    for(it=li.begin();it!=li.end();it++)
    {
	  if(it!=li.begin())
       cout<<" ";
       cout<<*it;//输出剩下的元素
	}
	cout<<endl;
  }
  
  
  }
    return 0;
}

F - 产生冠军

有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。

Input

输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。

Output

对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。

Sample

InputcopyOutputcopy
3
Alice Bob
Smith John
Alice Smith
5
a c
c d
d e
b e
a d
0
Yes
No

总结:set的简单应用。

#include<queue>
#include<string>
#include<stdio.h>
#include<iostream>
#include<list>
#include<set>
using namespace std;
int main()
{ 
  set<string>s1,s2;
  int n;
  while(cin>>n)
  {
  	if(n==0)
  	break;
    string a,b;
   for(int i=0;i<n;i++)
  {
  cin>>a>>b;
  s1.insert(a),s1.insert(b),s2.insert(b);//s1将所有元素加进去,s2加入失败者
  }
  if(s1.size()-s2.size()==1)//如果s1中所有元素比s2多一个则有结果
   cout<<"Yes"<<endl;
   else
   cout<<"No"<<endl;
   s1.clear();//对s1,s2进行清除
   s2.clear();
  }
  
    return 0;
}

G - Shopping

Every girl likes shopping,so does dandelion.Now she finds the shop is increasing the price every day because the Spring Festival is coming .She is fond of a shop which is called "memory". Now she wants to know the rank of this shop's price after the change of everyday.

Input

One line contians a number n ( n<=10000),stands for the number of shops.
Then n lines ,each line contains a string (the length is short than 31 and only contains lowercase letters and capital letters.)stands for the name of the shop.
Then a line contians a number m (1<=m<=50),stands for the days .
Then m parts , every parts contians n lines , each line contians a number s and a string p ,stands for this day ,the shop p 's price has increased s.

Output

Contains m lines ,In the ith line print a number of the shop "memory" 's rank after the ith day. We define the rank as :If there are t shops' price is higher than the "memory" , than its rank is t+1.

Sample

InputcopyOutputcopy
 
3
memory
kfc
wind
2
49 memory
49 kfc
48 wind
80 kfc
85 wind
83 memory
1
2

总结:map的简单应用

#include<queue>
#include<string>
#include<stdio.h>
#include<iostream>
#include<list>
#include<set>
#include<map>
using namespace std;
int main()
{ 
  map<string,int>shop;
  map<string,int>::iterator it;//迭代器
  int n;
  string s;
  int m;
  while(cin>>n)
  {
 
   for(int i=0;i<n;i++)
    cin>>s;
    cin>>m;
    int p;
    while(m--)//天数
    {
      for(int i=0;i<n;i++){
	  cin>>p>>s;
	  shop[s]+=p;}//s为商店名称,p为增加的价格
	
   int rank=1;
   for(it=shop.begin();it!=shop.end();it++)
  {
    if(it->second>shop["memory"])//it->second表示第二个元素
        rank++;
  }
   cout<<rank<<endl;
}
   shop.clear();
  }
    
    return 0;
}

H - Ignatius and the Princess II

Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess."

"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem?

Input

The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file.

Output

For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.

Sample

InputcopyOutputcopy
 
6 4
11 8
 
1 2 3 5 6 4
1 2 3 4 5 6 7 9 8 11 10

总结:直接采用algorithm下面的next_permutation()函数

#include<queue>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<list>
#include<set>
#include<map>
using namespace std;
int a[100000];
int main()
{ int n,m;
while(cin>>n>>m)
{
  for(int i=1;i<=n;i++)
    a[i]=i;
  int t=1;
  do{
    if(t==m)
       break;
    t++;
  
  }while(next_permutation(a+1,a+1+n));//对a[1]~a[n]元素进行排列
for(int i=1;i<=n;i++){
    if(i!=1)
     cout<<" ";//数据之间有空格
     cout<<a[i];
 }
 cout<<endl;
}
  
    return 0;
}

I - 排列2

Ray又对数字的列产生了兴趣:
现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。

Input

每组数据占一行,代表四张卡片上的数字(0<=数字<=9),如果四张卡片都是0,则输入结束。

Output

对每组卡片按从小到大的顺序输出所有能由这四张卡片组成的4位数,千位数字相同的在同一行,同一行中每个四位数间用空格分隔。
每组输出数据间空一行,最后一组数据后面没有空行。

Sample

InputcopyOutputcopy
 
1 2 3 4
1 1 2 3
0 1 2 3
0 0 0 0
 
1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321

1123 1132 1213 1231 1312 1321
2113 2131 2311
3112 3121 3211

1023 1032 1203 1230 1302 1320
2013 2031 2103 2130 2301 2310
3012 3021 3102 3120 3201 3210

总结:注意输出的格式

#include<queue>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<list>
#include<set>
#include<map>
using namespace std;
int a[5];
int main()
{ int index=0;
while(cin>>a[1]>>a[2]>>a[3]>>a[4])
{ 
   int s=0,p=100;
   for(int i=1;i<=4;i++)
     {s+=a[i];
	  if(a[i]!=0)
	   p=min(p,a[i]);//p用来记录除0最小的数,既第一个4位数的千位
	 }
    if(s==0)
     break;
  if(index)//用于控制数据之间有空格
   cout<<endl;
   int j=1;//用于控制在在数据后面输出空格
  do{
  	 int flag=1;
  	 if(a[1]==0)
		{flag=0;j=1;//如果第一个数为0,则设为不可输出,将j=1;
		 continue;
		}
	 if(a[1]!=p){//用于判断是否换行,记录前一个第一个数和现在要输出的第一个数比较,不同则换行
	 	if(flag==1){
         cout<<endl;
		 p=a[1];}
		 j=1;
		}
	if(flag==1&&j!=1)//用于换行	
       cout<<" ";
		      
     for(int i=1;i<=4;i++)//输出
          {
		    if(a[1]==0)
		      {flag=0;break;} 
	     	cout<<a[i];
		  }
	
    
  j++;
  }while(next_permutation(a+1,a+5));//对a[1]~a[4]之间的元素从小到大进行排列
  cout<<endl;
  index=1;
}
 
    return 0;
}

精典语录:生命真正的成熟,是历经沧桑之后的淡定,是风雨洗礼之后的清醒。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会敲代码的破茧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值