前言
不太好写的一章节~愿读者充满耐心地学习每一道题,如果是面对小测,可以提前准备一下,因为这一章不太容易在初次见到的时候马上做出来。
B001 快乐的蠕虫
题目描述
有一只快乐的蠕虫居住在一个m×n大小的网格中。在网格的某些位置放置了k块石头。网格中的每个位置要么是空的,要么放置了一块石头。当蠕虫睡觉时,它在水平方向或垂直方向上躺着,把身体尽可能伸展开来。蠕虫的身躯既不能进入到放有石块的方格中,也不能伸出网格外。而且蠕虫的长度不会短于2个方格的大小。 本题的任务是给定网格,要计算蠕虫可以在多少个不同的位置躺下睡觉。
输入
输入文件的第1行是一个整数t,1<=t<=11,表示测试数据的个数。每个测试数据的第1行为3个整数:m,n和k(0<=m,n,k<=200000),接下来有k行,每行为2个整数,描述了一块石头的位置(行和列,最左上角位置为(1,1))。
输出
对每个测试数据,输出占一行,为一个整数,表示蠕虫可以躺着睡觉的不同位置的数目。
样例输入 复制
1
5 5 6
1 5
2 3
2 4
4 2
4 3
5 1样例输出 复制
9
思路:
笔者觉得这题挺难写的,基本思路就是把网格四周一圈也当作石头,然后在内部通过x轴排序还有y轴排序的方式,分别去放蠕虫,然后计数,虽然很不喜欢这道题,但是好像考试考的概率特别大【悲】愿读者自求多福。
代码C++:
#include<bits/stdc++.h>
using namespace std;
typedef struct stone{
int x;
int y;
}s;
s st[200007];
bool cmp1(s a,s b){
if(a.y == b.y) return a.x < b.x;
return a.y < b.y;
}
bool cmp2(s a,s b){
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
void solve(){
int m,n,k;
cin >> m >> n >> k;
int cnt = 0;
for(int i = 0;i <= n + 1;i++){
st[cnt].x = 0,st[cnt].y = i;
cnt++;
st[cnt].x = m + 1,st[cnt].y = i;
cnt++;
}
for(int i = 0;i <= m + 1;i++){
st[cnt].x = i,st[cnt].y = 0;
cnt++;
st[cnt].x = i,st[cnt].y = n + 1;
cnt++;
}
for(int i = 1;i <= k;i++){
int x,y;
cin >> x >> y;
st[cnt].x = x,st[cnt].y = y;
cnt++;
}
sort(st,st + cnt,cmp1);
int ans = 0;
for(int j = 0;j < cnt - 1;j++){
if(st[j + 1].y == st[j].y && abs(st[j + 1].x - st[j].x) > 2){
ans++;
}
}
sort(st,st + cnt,cmp2);
for(int j = 0;j < cnt - 1;j++){
if(st[j + 1].x == st[j].x && abs(st[j + 1].y - st[j].y) > 2){
ans++;
}
}
cout << ans << "\n";
}
int main(){
int t;
cin >> t;
while(t--) solve();
}
B002 单词重组
题目描述
在美国数以百万计的报纸中,有一种单词游戏称为猜词。游戏的目标是猜谜,为了找出答案中缺少的字母,有必要对4个单词的字母顺序重新调整。在本题中,你的任务是编写程序实现对单词中的字母顺序重新调整。
输入
输入文件包含4部分: (1) 一部字典,包含至少1个单词,至多100个单词,每个单词占一行;
(2) 字典后是一行字符串“XXXXXX”,表示字典结束;
(3) 一个或多个被打乱字母顺序的“单词”,每个单词占一行,你必须整理这些字母的顺序;
(4) 输入文件的最后一样为字符串“XXXXXX”,代表输入文件结束。
所有单词,包括字典中的单词和被打乱字母顺序的单词,都只包含小写英文字母,并且至少包含一个字母,至多包含6个字母。字典中的单词不一定是按顺序排列的,但保证字典中的单词是唯一的。
输出
对输入文件中每个被打乱字母顺序的单词w,按字母顺序输出字典中所有满足以下条件的单词的列表:通过调整单词w中的字母顺序,可以变成字典中的单词。列表中的每个单词占一行。如果列表为空(即单词w不能转换成字典中的任何一个单词),则输出一行字符串“NOT A VALID WORD”。以上两种情形都在列表后,输出一行包含6个星号字符的字符串,表示列表结束。
样例输入 复制
tarp
given
score
refund
only
trap
work
earn
course
pepper
part
XXXXXX
resco
nfudre
aptr
sett
oresuc
XXXXXX样例输出 复制
score
******
refund
******
part
tarp
trap
******
NOT A VALID WORD
******
course
******
思路:
这道题笔者暂时只能想到这种做法,如果有更好的可以分享~
笔者这里是用map来实现的,就是给每个单词对应了一个排序后的映射,比如这里会认为abcd和dcba会有相同的映射即abcd。然后后续输出单词的时候,逐一输出map里相同映射的那些单词~
代码C++:
#include<bits/stdc++.h>
using namespace std;
map<string,string> mp;
int main(){
string s;
while(cin >> s){
if(s == "XXXXXX") break;
string str = s;
sort(s.begin(),s.end());
mp[str] = s;
}
while(cin >> s){
if(s == "XXXXXX") break;
int cnt = 0;
for (auto it = mp.begin(); it != mp.end(); ++it) {
// cout << it->first << " => " << it->second << '\n';
sort(s.begin(),s.end());
if(it -> second == s){
cnt++;
cout << it -> first << "\n";
}
}
if(cnt == 0){
cout << "NOT A VALID WORD\n******\n";
}else{
cout << "******\n";
}
}
}
B003 英文姓名排序
题目描述
在汉语里,对汉语姓名可以按拼音排序,也可以按笔画顺序排序。在英语里,对英语姓名主要按字母顺序排序。本题要求给定的一组英文姓名按长短顺序排序。
输入
输入文件中包含多个测试数据。每个测试数据的第1行是一个正整数N(0 < N < 100),表示该测试数据中英文姓名的数目;接下来有N行,每行为一个英文姓名,姓名中允许出现的字符有大小写英文字母、空格和点号(.),每个英文姓名长度至少为2、但不超过50.N=0表示输入结束。
输出
对输入文件中的每个测试数据,输出排序后的姓名。排序方法为:先按姓名长度从长到短的顺序排序,对长度相同的姓名,则按字母顺序排序。每2个测试数据的输出之间输出一个空行。
样例输入 复制
4
David A. Forsyth
Jean Ponce
Tom M. Mitchell
Thomas H. Cormen
0样例输出 复制
David A. Forsyth
Thomas H. Cormen
Tom M. Mitchell
Jean Ponce
思路:
这道题思路还是很简单的,就是排序,然后处理一下排序逻辑,但是因为阴间的一些换行符问题,这里不能用getchar(),所以用了getline去吞换行符。
代码C++:
#include<bits/stdc++.h>
using namespace std;
string str[1000];
bool cmp(string a,string b){
if(a.size() != b.size()) return a.size() > b.size();
return a < b;
}
int main(){
int n;
while(cin >> n){
if(!n) break;
string s;
getline(cin,s);
for(int i = 1;i <= n;i++){
getline(cin,s);
str[i] = s;
}
sort(str + 1,str + n + 1,cmp);
for(int i = 1;i <= n;i++){
cout << str[i] << "\n";
}
cout << "\n";
}
}
B004 DNA排序
题目描述
一个序列的逆序数定义为序列中无序元素对的数目。例如,在字符序列DAABEC中,逆序数为5,因为字符D比它右边的4个字符大,而字符E比它右边的1个字符大。字符序列AACEDGG只有1个逆序,即E和D,它几乎是已经排好序的,而字符序列“ZWQM”有6个逆序,它是最大程度的无序,即有序序列的逆序。 在本题中,你的任务是对DNA字符串(只包含字符“A”、“C”,“G”和“T”)进行排序。注意不是按照字母顺序,而是按照逆序数从低到高进行排序,所有字符串的长度都一样。
输入
输入文件中包含多组测试数据。每组测试数据的格式为:第1行为2个整数,正整数n(0 < n <= 50,表示字符串的长度)和正整数m(1 < m <= 100,表示字符串的数目);然后是m行,每一行为一个字符串,长度为n。
输出
对应到输入文件中的N组测试数据,输出也有N组,每2组输出之间有一个空行。对每组输入数据,按逆序数从低到高输出各字符串,如果2个字符串的逆序数一行,则按输入时的先后顺序输出。
样例输入 复制
10 5
TTTTGGCCAA
TTTGGCCAAA
GATCAGATTT
CCCGGGGGGA
ATCGATGCAT样例输出 复制
CCCGGGGGGA
GATCAGATTT
ATCGATGCAT
TTTTGGCCAA
TTTGGCCAAA
思路:
笔者最开始还想着分两个数组进行处理,但是后面发现排序很难同步处理,干脆就换成结构体排序的写法了。
代码C++:
#include<bits/stdc++.h>
using namespace std;
struct node{
string s;
int cnt = 0;
}node[1000];
bool cmp(struct node a,struct node b){
return a.cnt < b.cnt;
}
int main(){
int n,m;
while(cin >> n >> m){
for(int i = 1;i <= m;i++){
string s;
cin >> s;
node[i].s = s;
int cnt = 0;
for(int j = 0;j < n;j++){
for(int k = j + 1;k < n;k++){
if(s[j] > s[k]) cnt++;
}
}
node[i].cnt = cnt;
}
sort(node + 1,node + m + 1,cmp);
for(int i = 1;i <= m;i++){
cout << node[i].s << "\n";
}
cout << "\n";
}
}
B005 体重排序
题目描述
作为一台很受欢迎的脱口秀节目的主持人,你正在做一期关于节食的节目。你的嘉宾是Kevorkian博士。他最近推出了一项减肥计划“Do You Want To Diet?”,这项计划向它的用户保证每天减肥1磅。 节目录制那天,你准备让一些使用Kevorkian博士减肥计划的节食者上台秀一下。你准备按他们的体重的递减顺序来安排他们出场的先后顺序。问题是他们报名时只提供了以下信息:姓名,节食的天数,节食前的体重。你要根据他们节食的天数来计算他们现在的体重。所有的节食者每天减肥1磅。
输入
输入文件包含至多100个测试数据。测试数据之间没有空行。每个测试数据包含3部分: 第1行为START; 接下来为节食者列表:包含110行,每行描述一名节食者,包括姓名、节食的天数和节食前的体重。其中姓名为120个数字、字母字符组成的字符串;节食的天数不超过1000天;节食前的体重不超过10,000。 最后一行为END。
输出
对每个测试数据,根据各节食者现在体重的递减顺序列出节食者的名字,每个节食者的名字占一行。每2个测试数据的输出之间有一个空行。
样例输入 复制
START
Joe 10 110
END
START
James 100 150
Laura 100 140
Hershey 100 130
END样例输出 复制
Joe
James
Laura
Hershey
思路:
这题主要是处理START和END有点麻烦,可以参考笔者这里的做法~
代码C++:
#include<bits/stdc++.h>
using namespace std;
struct node{
string name;
int day = 0;
int w = 0;
}node[10000];
bool cmp(struct node a,struct node b){
return a.w - a.day > b.w - b.day;
}
int main(){
string start;
string end;
while(cin >> start){
int cnt = 0;
string name;
int day = 0;
int w = 0;
while(cin >> name){
if(name == "END") break;
cin >> day >> w;
cnt++;
node[cnt].name = name;
node[cnt].day = day;
node[cnt].w = w;
}
sort(node + 1,node + cnt + 1,cmp);
for(int i = 1;i <= cnt;i++){
cout << node[i].name << "\n";
}
cout << "\n";
}
}
B006 俄罗斯套娃
题目描述
俄罗斯套娃大家应该都玩过。是一个按照大小顺序可以嵌套在一起的玩具。现在有一个被拆开的俄罗斯套娃摆到了你的好友面前,但是,要想把它重新变成一个娃娃,必须要满足这样的规则: 1.娃娃的大小必须是从小到大排列好的。 2.你每次只可以交换相邻的两个娃娃。 这样的规则使你的好友变得很烦躁,假设娃娃的个数为n,如果交换娃娃的次数超过n*(n – 1) / 2 – 1次,那么你的好友就会烧掉这些娃娃。但是她很珍惜这些娃娃。现在她向你询问,她是否不会烧掉这个俄罗斯套娃?
输入
一个整数n(n <= 1000) 接下来n个数Si,Si表示当前位置娃娃大小。(Si不一定小于n)。
输出
如果好友不会烧掉娃娃输出”YES”(没有引号),反之输出”NO”(没有引号)。
样例输入 复制
6
6 5 4 3 2 1样例输出 复制
NO
思路:
笔者最开始想得乱七八糟的,结果暴力排序就可以了hhh
代码C++:
#include<bits/stdc++.h>
using namespace std;
int s[1000];
int main(){
int n;
cin >> n;
for(int i = 0;i < n;i++){
cin >> s[i];
}
int cnt = 0;
for(int i = 0;i < n - 1;i++){
for(int j = 0;j < n - 1- i;j++){
if(s[j] > s[j + 1]){
int temp = s[j];
s[j] = s[j + 1];
s[j + 1] = temp;
cnt++;
}
}
}
cout << ((cnt > n * (n - 1) / 2 - 1) ? "NO\n" : "YES\n");
}
B007 组合数字
题目描述
现在给你n个正整数,a1,a2,a3……..an,请你把它们首尾连接到一起,组成一个最小的正整数(可能会超出long long)。
输入
第一行有一个整数,表示数字个数 n。 第二行有 n 个整数,表示给出的 n 个整数 ai(1 <= n <= 20,1 <= ai <= 1e9)。
输出
一个正整数,表示最小的整数。
样例输入 复制
3
13 312 343样例输出 复制
13312343
思路:
很经典的字符串拼接比较的方法就是
bool cmp(string a,string b){ return a + b < b + a; }一定要理解哦~
代码C++:
#include<bits/stdc++.h>
using namespace std;
string a[1000];
bool cmp(string a,string b){
return a + b < b + a;
}
int main(){
int n;
cin >> n;
for(int i = 1;i <= n;i++){
cin >> a[i];
}
sort(a + 1,a + n + 1,cmp);
for(int i = 1;i <= n;i++){
cout << a[i];
}
}