第一次csp模拟

Problem——A-咕咕东的奇遇

问题描述

咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。
咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。

输入格式

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

输出格式

输出最少要转的次数。

问题分析

首先输入一个字符串,然后挨个处理字符直到为空。记录现在指向的字符,然后遍历,利用ASCII中字符与数字的转换的大小来确定需要转动多少次。(即用当前字符的大小减去下一个字符的大小,然后判断其大小与转动次数的关系,如果差值大于13,就可以逆向转动,这样转动的次数更少)然后累加每次需要转动的次数,并更新当前指向的字符即可。

代码

#include<iostream>
using namespace std;
#include<cmath> 
int main()
{
	char a[100000];
	int step=0;
	int shu;
	cin>>a;
	int i=0;
	char now='a';
	while(a[i]!='\n'&&a[i]!='\0'&&a[i]!='\t')
	{
		shu=abs(a[i]-now);
		//shu=abs(shu);
		if(shu>13)shu=26-shu;
		step=step+shu;
		now=a[i];
		//cout<<shu<<" =shu,   step=  "<<step<<endl;
		i++;
	}
	cout<<step<<endl;
	return 0;
} 

遇到的问题

不是很清楚利用cin输入字符串最后的结束符号是什么,于是我都写了。免得出错。还有个很悲催的问题,我没有看数据大小,就导致了我数组溢出,嘶,难受。

Problem——B-咕咕东想吃饭

题目描述

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

输入格式

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

输出格式

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

问题分析

转换一下两种买东西的模式,即分为,偶数个的买法和奇数个的买法。然后就是奇数个的买法会导致下一天还需要购买的生煎的数目的奇偶性改变一下即可。
再方便理解一下,就可以假设我们的主角特别喜欢第一种买法,只有到了特别的时候(比如某天只差一个生煎就买齐的时候)才使用第二种买法。因为只需要判断是否可行,所以不需要太过于思考具体是怎样买的,无论如何最后也会被归为偶数和奇数的问题。
只需要一个循环,当第i天需要还需要买m个生煎时,如果m是偶数,不做任何处理,如果m为奇数,那么第i+1天就少买一个生煎,留一个今天买一赠一。直到最后一天是否还需要买偶数个,是的话答案就是“YES”,否则就是“NO”。

代码

#include<iostream>
using namespace std;
int n;
int *a;
bool pan=false;
void dfs(int i,int buy)//days    already buy
{
	if(i==n-1)
	{
		if((a[i]-buy)%2==0&&a[i]-buy>=0)
		{
			pan=true;
			//cout<<11<<endl;
		}
		//cout<<i<<" =i     sheng="<<a[i]-buy<<endl; 
		return;
	}
	else
	{
		if(a[i]-buy<0)
			return;
			
		int shu=a[i]-buy;
		if(shu%2==0)
			dfs(i+1,0);
		else
			dfs(i+1,1);	
	}
	return;
}
int main()
{
	
	cin>>n;
	a=new int [n+1];
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	dfs(0,0);
	if(pan)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	
	return 0;
} 

遇到的问题

一开始把题目理解成了,求每天的各种买法买的的生煎的方法组合,就直接用了深搜,每天买a个就会有a/2个买东西的方法。导致复杂度疯狂上涨。后来再次读题才发现,这只是在问我是否有可行的买法,而不是让我遍历所有的买法。所以只需要判断每一天的奇偶即可,完全不需要那么复杂的算法。

Problem——C

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题分析

首先这是一个搜索问题,毋庸置疑,实现我采用了宽搜的办法(是为了后面的剪枝)用结构体来储存每次射线要开始分裂的点的状态。(包括:位置,方向,第几次分裂)
然后先默认起始位置在[155,155]上,因为最多往一个方向走上150步,就选了最中间的点来作为起始点,将当时的状态入队。
方向是用的两个数组,dx,dy所存放的数来表示的,i序号的方向的分裂方向就是相邻着的其他两个方向。以此作为展开,入队,从而展开宽搜。
优化的方式,找到有从同一顶点出发,方向一样,需要走的路程也一样(即在同一层)的顶点,并把它去掉。为了节约一下内存,我的judge并没有使用四维数组,而是采用的三维数组。以它的值(上一个这么走的是第几次的分裂)来判断是否需要去掉。
剩下的就是按照普通的搜索方法来的。

代码

#include<iostream>
using namespace std;
#include<queue>
int n;
int* a;
int vis[310][310];
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};
struct node
{
	int x;
	int y;
	int fang;//小于8 
	int step;//小于30 
};
int judge[310][310][8]; 
queue<node*> q;

void bfs()
{
	//cout<<1111<<endl;
	node *currentnode;
	node *newnode;
	newnode=new node;
	newnode->x=155;
	newnode->y=155;
	newnode->fang=0;
	newnode->step=1;
	//cout<<1111<<endl;
	judge[155][155][0]=1;
	q.push(newnode);
	//cout<<q.size()<<endl;
	while(q.size()!=0)
	{
		currentnode=q.front();
		q.pop();
		//cout<<currentnode->x<<"    "<<currentnode->y<<"      "<<currentnode->step<<"      "<<currentnode->fang<<endl;
		if(currentnode->step==n+1)
		{
				break;
		}
		else
		{
			//judge[currentnode->x][currentnode->y]=currentnode->step+currentnode->fang*100;
			int nx,ny;
			nx=currentnode->x;
			ny=currentnode->y;
			for(int i=0;i<a[currentnode->step];i++)
			{
				nx=nx+dx[currentnode->fang];
				ny=ny+dy[currentnode->fang];
				vis[nx][ny]=1;
				//cout<<"    nx="<<nx<<"     ny="<<ny<<endl;
			}
			int nfang1,nfang2;
			nfang1=(currentnode->fang+1)%8;
			nfang2=(currentnode->fang+7)%8;
			if(judge[nx][ny][nfang1]!=currentnode->step+1)
			{
				judge[nx][ny][nfang1]=currentnode->step+1;
				newnode=new node;
				newnode->x=nx;
				newnode->y=ny;
				newnode->step=currentnode->step+1;
				newnode->fang=nfang1;
				q.push(newnode);
				//cout<<"newnopde:"<<newnode->x<<"   "<<newnode->y<<"   "<<newnode->step<<"    "<<newnode->fang<<endl;
			}
			if(judge[nx][ny][nfang2]!=currentnode->step+1)
			{
				judge[nx][ny][nfang2]=currentnode->step+1;
				newnode=new node;
				newnode->x=nx;
				newnode->y=ny;
				newnode->step=currentnode->step+1;
				newnode->fang=nfang2;
				q.push(newnode);
				//cout<<"newnopde:"<<newnode->x<<"   "<<newnode->y<<"   "<<newnode->step<<"    "<<newnode->fang<<endl;
			}
		}
	}
}
int main()
{
	cin>>n;
	a=new int [n+1];
	for(int i=0;i<310;i++)//初始化 
		for(int j=0;j<310;j++)
			vis[i][j]=0;

	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	int x=155;
	int y=155;
 	bfs();
 	int step=0;
 	for(int i=0;i<310;i++)//初始化 
		for(int j=0;j<310;j++)
			if(vis[i][j]==1)step++;	
	cout<<step<<endl; 
	return 0;
} 

遇到的问题

最开始只是采用了宽搜,因为没想到后面会有那么多的重复,也就没有去思考到底怎么去优化搜索。于是就很悲惨的超时了。最开始写的代码比较复杂,就是脑子里不清楚怎么处理方向的事,于是写了八个if,现在想想真是太费力了。后来重写代码,才把方向的问题简化了一下,让自己的代码看着少一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值