A题 咕咕咚的奇遇
- 题意:
有一个由26个字母组成的圈,如下图所示
设起始位置为 ‘a’ ,从该字母圈中取出一个字符串(即轮流取出每个字符),求最小的步数是多少。
输入要求:
输入一行,为一个字符串
输出要求:
输出需要的最小步数
sample input:
hzet
sample output:
31
思路:
每次从所在的位置location,到目的位置 a[i],需要的步数为 abs(location - a[i]) 或 26 - abs(location - a[i]),对每个字母进行判断即可得到最小步数。
代码:
#include <iostream>
#include <math.h>
using namespace std;
char str[10000];
int main(){
cin>>str;
int i=0;
char current='a';
int step=0;
while(str[i]!='\0'){
if(abs(str[i]-current)<=13){
step=step+abs(str[i]-current);
}
else{
step=step+26-abs(str[i]-current);
}
current=str[i];
i++;
}
cout<<step<<endl;
}
B题:咕咕咚想吃饭
题意:
咕咕咚需要买生煎 n 天,每天需要 a[i] 个生煎,生煎店出售方式为:一次卖两个,或者一次卖一个加一张券(仅第二天可用),要求:判断出咕咕咚是否能每天都吃到需要的生煎,并且没有浪费的生煎或券。
输入要求:
第一行输入天数n,第二行输入 n 个数,分别对应第 i 天需要吃的生煎。
输出要求:
根据是否能每天吃到所需生煎且无浪费,输出“YES”或者“NO”。
sample input:
4
1 2 1 2
sample output:
YES
思路:
- 定义一个 bool 型变量 quan,用于判断当天是否有券。
- 使用一个 while 循环,对每一天进行判断:
1、当天有券且当天所需生煎为奇数个;
2、当天有券且当天所需生煎为偶数个;
3、当天无券且当天所需生煎为奇数个;
4、当天无券且所需生煎为偶数个。
代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> a;
int main(){
int n,a_;
cin>>n;
//int a[n];
for(int i=0;i<n;i++){
cin>>a_;
a.push_back(a_);
}
bool quan=false;//开始没有券
int date=0;
while(date<n){
if(quan==true){//当天有券
if(a[date]%2==1){//当天奇数个,而且有券
//把券用了
quan=false;
}
if(a[date]%2==0){
if(a[date]==0){//不吃,但是有券
cout<<"NO"<<endl;
return 0;
}
quan=true;
if(date==n-1){//最后一天还有券
cout<<"NO"<<endl;
return 0;
}
}
}
else{//当天没有券
if(a[date]%2==1){//当天吃奇数个
quan=true;
if(date==n-1){
cout<<"NO"<<endl;
return 0;
}
}
if(a[date]%2==0){
quan=false;
}
}
date++;
}
cout<<"YES"<<endl;
}
C题 可怕的宇宙射线
题意:
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的 左右45°方向分裂出两条宇宙射线。宇宙射线会分裂 n 次,每次分裂后会在分裂方向前进
a
i
a_i
ai 个单位长度。
要求:计算在结束分裂后,有多少位置有宇宙射线。
输入要求:
输入第一行包含一个正整数 n,表示宇宙射线会分裂 n 次,第二行包含n个正整数,第 i 个数 表示第 i 次分裂的宇宙射线会在它原方向上继续走多少个单位长度。
输出要求:
输出一个 ans,表示有多少位置有宇宙射线。
sample input:
4
4 2 2 3
sample output:
39
射线分裂过程如下图所示:
数据点说明:
- 10%:n <= 10
- 40%:n <= 20
- 100%: n <= 30
思路:
- 该题可以使用 bfs 或者 dfs,这里选择了 dfs,但是若直接使用 dfs,不进行剪枝,只能拿到 40 分,在 n <= 30
的数据中会发生超时错误,所以需要进行对其进行适当的剪枝操作。 - 若在同一个点,做方向相同,长度相等的分裂,则可以不再做此次分裂,即可减少大量操作。为了判断是否做过相同的分裂,定义一个 bool 类型四维数组 vis[300][300][31][8]。
代码:
#include <iostream>
#include <queue>
using namespace std;
struct point {
int x, y;
int num;//用来判断该点是第几次分裂到达的点
point() {}
point(int x_, int y_, int _num = 0) {
x = x_;
y = y_;
num = _num;
}
};
int n;
//从向上开始顺时针的八种方向
int dx[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
int dy[] = { 1, 1, 0, -1, -1, -1, 0, 1 };
int l[30];
int ans = 0;
queue<point> q;
bool vis[300][300][31][8];
bool reach[300][300];
//起点 (150,150)
//dfs
void split(point p, int direction, int k) {
if (vis[p.x][p.y][k][direction]) return;
vis[p.x][p.y][k][direction] = true;
for (int i = 0; i < l[k]; i++) {
if (reach[p.x + dx[direction] * (i + 1)][p.y + dy[direction] * (i + 1)] == false) {
reach[p.x + dx[direction] * (i + 1)][p.y + dy[direction] * (i + 1)] = true;
ans++;
}
}
point p_(p.x + dx[direction] * l[k], p.y + dy[direction] * l[k]);
int direc1, direc2;
switch (direction) {
case 0: {
direc1 = 7;
direc2 = 1;
break;
}
case 7: {
direc1 = 6;
direc2 = 0;
break;
}
default: {
direc1 = direction - 1;
direc2 = direction + 1;
break;
}
}
if (k < n - 1) {
split(p_, direc1, k + 1);
split(p_, direc2, k + 1);
}
return;
}
int main() {
cin >> n;
//初始化
for (int i = 0; i < n; i++) {
cin >> l[i];
}
for (int i = 0; i < 300; i++) {
for (int j = 0; j < 300; j++) {
reach[i][j] = false;
for (int k = 0; k < 31; k++) {
for (int t = 0; t < 8; t++)
vis[i][j][k][t] = false;
}
}
}
point p(150, 150);
split(p, 0, 0);
cout << ans << endl;
}