程序设计思维 week4 csp模拟

A 咕咕东的奇遇

题意

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

加个示意图
输入格式
输入只有一行,是一个字符串。

输出格式
输出最少要转的次数。

样例输入
zeus
样例输出
18
数据点 字符串长度
1,2 小于等于10
3,4,5 小于等于100
6,7,8,9,10 小于等于10000

做法

贪心,每次选择顺时针或逆时针差距最小的作为步长。

代码

#include<iostream>
using namespace std;
string s;
int main() 
{
	cin>>s;
	char temp='a';
	int ssz,nsz,ans=0;
	for(int i=0;i<s.length();i++)
	{
		ssz=abs(s[i]-temp);
		nsz=26-ssz;
		ans+=min(ssz,nsz);
	//	cout<<ssz<<" "<<nsz<<endl; 
		temp=s[i];
	}
	cout<<ans<<endl;
}

B 咕咕东想吃饭

题意

题目描述
咕咕东考试周开始了,考试周一共有n天。他不想考试周这么累,于是打算每天都吃顿好的。他决定每天都吃生煎,咕咕东每天需要买a_ia
i

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

个生煎。

输入格式
输入两行,第一行输入一个正整数n(1<=n<=100000)(1<=n<=100000),表示考试周的天数。

第二行有n个数,第i个数a_i(0<=a_i<=10000)a
i

(0<=a
i

<=10000)表示第i天咕咕东要买的生煎的数量。

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

样例输入1
4
1 2 1 2
样例输出1
YES
样例输入2
3
1 0 1
样例输出2
NO
数据点 n(上限) a_ia
i

(上限)
1,2 10 10
3,4,5 1000 10
6,7 10 10000
8,9,10 100000 10000

做法

也是贪心。注意到奇偶性。
构造如下方法。
在用完前一天优惠券时,若还需要买偶数个生煎,则直接采用1方案。
若有奇数个,则先用1方案,剩一个用2方案。
以上是对第二天影响最小的方案。

代码

#include<iostream>
using namespace std;
int n,a[100009];
int main()
{
	cin>>n;
	int last=0,temp=0;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n-1;i++)
	{	temp=a[i]-last;
		if(temp<0)
		{
			cout<<"NO"<<endl;
			return 0;
		}
		if(temp%2==0)
		{
			last=0;
		}
		else if(temp%2==1)
		{
			last=1;
		}
	}
	temp=a[n]-last;
		if(temp<0)
		{
			cout<<"NO"<<endl;
			return 0;
		}
		if(temp%2==0)
		{
			last=0;
			cout<<"YES"<<endl;
		}
		else if(temp%2==1)
		{
			last=1;	
			cout<<"NO"<<endl;
		}
	
}

C 宇宙射线

题意

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

做法

直接bfs如下面第一份代码,会指数级爆炸。
注意到,每次产生子节点时,是对称的。
最大的重复可能性是,相同子节点下一层的扩展是相同的。
因此考虑到用四维数组记录是否下一层扩展相同,如果已经被扩展了,则不加入bfs。(第二份代码)

代码

朴素bfs(爆内存,指数爆炸)

#include<iostream>
#include<queue>
using namespace std;
bool vis[3300][3300];
int n,a[40],ans,xxx,yyy;


int dx[]={0,1,1,1,0,-1,-1,-1};
int dy[]={1,1,0,-1,-1,-1,0,1};
struct dj{
	int num;
	int fx;
	int x,y;
};
void bfs()
{
	dj temp;
	temp.num=1;
	temp.fx=0;
	temp.x=160;
	temp.y=160; 
	queue<dj>q;
	q.push(temp);
	
	while(!q.empty())
	{
		dj now=q.front();
		q.pop();
		xxx=now.x;
		yyy=now.y;

		for(int k=1;k<=a[now.num];k++)
		{	xxx=xxx+dx[now.fx];
			yyy=yyy+dy[now.fx];
			if(vis[xxx][yyy]==false)
			{
				ans++;
				vis[xxx][yyy]=true; 
			}
		}
		if(now.num<=n)
		{
			dj n1,n2;
			n1.num=now.num+1;	
			n1.fx=(now.fx+1)%8;
			n1.x=xxx;
			n1.y=yyy;
			n2.num=now.num+1;	
			n2.fx=(now.fx+7)%8;
			n2.x=xxx;
			n2.y=yyy;
			q.push(n1);
			q.push(n2);			
		}
	}
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		//cout<<a[i];
	 } 
	 bfs();
	cout<<ans<<endl; 
	 
}

剪枝

#include<iostream>
#include<queue>
using namespace std;
bool vis[330][330][40][10];
int n,a[40],ans,xxx,yyy;


int dx[]={0,1,1,1,0,-1,-1,-1};
int dy[]={1,1,0,-1,-1,-1,0,1};
struct dj{
	int num;
	int fx;
	int x,y;
bool operator==(dj&p)
{
	if(num==p.num&&fx==p.fx&&x==p.x&&y==p.y)return 1;
	else return 0;
}
};

void bfs()
{
	dj temp;
	temp.num=1;
	temp.fx=0;
	temp.x=160;
	temp.y=160; 
	queue<dj>q;
	q.push(temp);
	vis[temp.x][temp.y][temp.num][temp.fx]=true;
	while(!q.empty())
	{
		dj now=q.front();
		q.pop();
		xxx=now.x;
		yyy=now.y;


		for(int k=1;k<=a[now.num];k++)
		{	xxx=xxx+dx[now.fx];
			yyy=yyy+dy[now.fx];
			if(vis[xxx][yyy][0][0]==false)
			{
				ans++;
				vis[xxx][yyy][0][0]=true; 
			}
		}
	 
		if(now.num<n)
		{
			dj n1,n2;
			n1.num=now.num+1;	
			n1.fx=(now.fx+1)%8;
			n1.x=xxx;
			n1.y=yyy;
			n2.num=now.num+1;	
			n2.fx=(now.fx+7)%8;
			n2.x=xxx;
			n2.y=yyy;
			if(vis[n1.x][n1.y][n1.num][n1.fx]==false)
				{
					vis[n1.x][n1.y][n1.num][n1.fx]=true;
				q.push(n1);
				}

			if(vis[n2.x][n2.y][n2.num][n2.fx]==false)
				{vis[n2.x][n2.y][n2.num][n2.fx]=true;
				q.push(n2);		
				}
			
		}
	}
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		//cout<<a[i];
	 } 
	 bfs();
	cout<<ans<<endl; 
	 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值