week4-CSP测验1

咕咕东的奇遇

题意:

一个圆环包含26个英文字母,顺时针从a到z排列,有一个指针指向a,每次可以顺时针或逆时针旋转一格。如a顺时针旋转到z,逆时针旋转到b。现在有一个字符串(长度<=10000),请输出要得到这个字符串最少需要旋转的次数。

输入:
输入只有一行,是一个字符串。

输出:
输出最少要转的次数。


思路:

对该字符串每个字母进行遍历,将起点b初始化为0 ,利用ascII码将字母-‘a’从而变成数字(结果记为c)。再利用函数min(绝对值(c-b),26-绝对值(c-b))找到最少旋转的次数,再将新的起点记为c。通过累计旋转的次数得到最终的结果。


代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define _for(i,a,b) for(int i=a;i<b;i++)
using namespace std;
char s[10010];
int main()
{
	int count=0;
	int b=0;
	int c;
	cin>>s;
	_for(i,0,strlen(s))
	{
		c=s[i]-'a';
		count=count+min(abs(c-b),26-abs(c-b));
		b=c; 
	}
	cout<<count<<endl;
	return 0;
	
}

B - 咕咕东想吃饭

题意:

咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买ai个生煎。但是生煎店为了刺激消费,只有两种购买方式:①在某一天一次性买两个生煎。②今天买一个生煎,同时为明天买一个生煎,店家会给一个券,第二天用券来拿。没有其余的购买方式,这两种购买方式可以用无数次,但是咕咕东是个节俭的好孩子,他训练结束就走了,不允许训练结束时手里有券。咕咕东非常有钱,你不需要担心咕咕东没钱,但是咕咕东太笨了,他想问你他能否在考试周每天都能恰好买ai个生煎。

Input:
输入两行,第一行输入一个正整数n(1<=n<=100000),表示考试周的天数。
第二行有n个数,第i个数ai(0<=ai<=10000)表示第i天咕咕东要买的生煎的数量。

Output:
如果可以满足咕咕东奇怪的要求,输出"YES",如果不能满足,输出“NO”。(输出不带引号)


思路:

1.通过判断最后手里是否有券来确定满足要求。
2.如果第一天买生煎,看买生煎的个数,从第一天开始,当天买的生煎除以二得到的余数为1,则证明有券,不买就废掉,拿第二天的生煎数可以-1。此时判断到第二天,如果第二天的生煎数<0,那就代表券没有,不符合条件,然后重复以上过程,直至最后一天,如果最后一天买的生煎以二得到的余数为0,则手里没券,符合条件,否则手里就有多余的券,不满足条件。由此得到最终结果
3.由于判断过程中没有考虑周到,结果只得了70分,原因在于a[n+1]未初始化,以至于无法判断是否小于0。

	if(a[n+1]<0) cout<<"NO"<<endl;

修改后的代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#define _for(i,a,b) for(int i=a;i<b;i++)
using namespace std;
int a[100001];
int main()
{
	int n;
	cin>>n;
	_for(i,0,n)
	{
		cin>>a[i];
	}
	_for(i,0,n)
	{
		if(a[i]<0)
		{
			cout<<"NO"<<endl;
			exit(0);
		}
		if(a[i]%2==1)
		{
			a[i+1]--;
		}
			
				
	}
	if(a[n-1]%2==0) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	return 0;
}

C - 可怕的宇宙射线

众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂n 次,每次分裂后会在分裂方向前进 ai个单位长度。
现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。

输入:
输入第一行包含一个正整数n(n<=30) ,表示宇宙射线会分裂n次。
第二行包含n个正整数a1,a2…an,第 i个数ai 表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度。

输出:
输出一个数 ans,表示有多少个位置会被降智打击。


思路:

这个题是需要向几个方向同时延伸,就如同迷宫一样可以前后左右四个方向,所以可以用DFS来解决,这时候可以设置一个二维数组来记录射线是否经过,也能避免射线重复。每次射线处理当前方向的宇宙射线会到达的位置和到达终点之后分裂出来的两个方向然后对另外两个方向进行处理。
思路是有了,不过处理的时候因为时间问题和经验不足写的比较麻烦,没有记录好坐标,导致经过的点不会重复,再者就是时间复杂度太大。


WA的代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define _for(i,a,b) for(int i=a;i<b;i++)
using namespace std;
int a[35];
bool vis[1000][1000]={false};
queue<int> q[35];
int main()
{
	int n;
	int count=0; 
	vis[500][500]=true;
	int x=500,y=500;
	q[0].push(1);
	cin>>n;
	_for(i,0,n)
		cin>>a[i];
	_for(i,0,n)
	{
		while(!q[i].empty())
		{
			switch(q[i].back())
			{
				case 1:
					q[i+1].push(2);
					q[i+1].push(8);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x][y+j]!=true)
						{
							vis[x][y+j]=true;
							count++;
						}
					}
					y=y+a[i];
					q[i].pop();
					break;
				case 2:
					q[i+1].push(1);
					q[i+1].push(3);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x+j][y+j]!=true)
						{
							vis[x+j][y+j]=true;
							count++;
						}
					}
					x=x+a[i];
					y=y+a[i];
					q[i].pop();
					break;
				case 3:
					q[i+1].push(2);
					q[i+1].push(4);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x+j][y]!=true)
						{
							vis[x+j][y]=true;
							count++;
						}
					}
					x=x+a[i];
					q[i].pop();
					break;
				case 4:
					q[i+1].push(3);
					q[i+1].push(5);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x+j][y-j]!=true)
						{
							vis[x+j][y-j]=true;
							count++;
						}
					}
					x=x+a[i];
					y=y-a[i];
					q[i].pop();
					break;
				case 5:
					q[i+1].push(4);
					q[i+1].push(6);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x][y-j]!=true)
						{
							vis[x][y-j]=true;
							count++;
						}
					}	
					y=y-a[i];
					q[i].pop();
					break;
				case 6:
					q[i+1].push(5);
					q[i+1].push(7);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x-j][y-j]!=true)
						{
							vis[x-j][y-j]=true;
							count++;
						}
					}
					x=x-a[i];
					y=y-a[i];
					q[i].pop();
					break;
				case 7:
					q[i+1].push(8);
					q[i+1].push(6);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x-j][y]!=true)
						{
							vis[x-j][y]=true;
							count++;
						}
					}		
					x=x-a[i];
					q[i].pop();
					break;
				case 8:
					q[i+1].push(1);
					q[i+1].push(7);
					for(int j=1;j<=a[i];j++)
					{
						if(vis[x-j][y+j]!=true)
						{
							vis[x-j][y+j]=true;
							count++;
						}
					}	
					x=x-a[i];
					y=y+a[i];
					q[i].pop();
					break;
				default:
					break; 
				}
			}
		}
	cout<<count<<endl;
	return 0;
		
}

没有记录好位置导致程序出错,后来修改了好几次没能把程序改正确,就求助了同学的代码,看了他的思路,可以如同迷宫一样设置好八个方向的位置

const int dx[8]={0,1,1,1,0,-1,-1,-1};
const int dy[8]={1,1,0,-1,-1,-1,0,1};

同时利用

const int dirction[8]={0,1,2,3,4,5,6,7};

并将其保存在结构体当中,这样可以不用使用switch
每个direction分裂时会向相邻两个数的方向,只需要将0 的两个方向设置为1和7;7相邻的两个方向设置为0和6即可。由于时间原因,没能写出正确的代码,自己也需要加强码力,提高自己的水平。

发布了7 篇原创文章 · 获赞 0 · 访问量 123

猜你喜欢

转载自blog.csdn.net/weixin_44465341/article/details/104981368