2022蓝桥杯

I - The Way to Home

小明在一个数轴上,他现在要从点 1跳到点 n,他每次可以向右跳不超过d个单位。比如,他可以从点x跳到点 x + a,a是一个在1到d之间的整数。特别地,小明只能在有标记的点上停留。保证点 1和点n有标记。请输出小明到达点 n的最小跳跃次数。

Input
输入第一行包含两个整数n和d (2 ≤ n ≤ 100, 1 ≤ d ≤ n - 1),分别表示小明想跳去的点以及一次跳跃的最大距离。

第二行是一个长度为n的字符串s,只包含0和1。字符串s中的字符为1,代表对应位置有标记;否则没有。输入保证s的第一个字符和最后一个字符等于1。

Output
如果小明不能到达目的地,输出-1

否则,输出小明到达目的地的最小跳跃次数

Sample 1
8 4
10010101
2

Sample 2
4 2
1001
-1

Sample 3
8 4
11100101
3

Sample 4
12 3
101111100101
4

Note
在样例1中,小明可以从点 1 跳3个单位到点 4 ,再从点 4跳4个单位到点 8。在样例2中,小明不能到达点 n,因为它至少需要跳3个单位,但它最多只能跳2个单位。

先来最简单的暴力

AC代码:

#include<iostream>
using namespace std;
int main()
{
    char s[102];
    int n,d;
    cin>>n>>d;
    getchar();//吸收回车//用于数字和字符输入之间
    for(int i = 1; i <= n; i++)
       cin>>s[i];
    int i = 1;
    int ans = 0;//记录最小跳跃次数
    while(i <= n)
    {
        int j = i + d;//每次从起点跳最远到达的下标
        if(j > n) //如果从起点跳的最远下标超过了n肯定可达并结束
        {
            ans++;
            break;
        }
        int flag = 0;
        while(j > i)//从大到小遍历
        {
            if(s[j] == '1') //找到第一个1停止
            {
                ans++;
                flag = 1;//标记这次跳跃能否执行
                i = j;//记录当前位置
                break;
            }
            j--;//不满足就减小距离
        }
        if(i == n)//到达就结束
            break;
        if(!flag)//跳跃不成功
        {
            cout<<"-1"<<endl;
            return 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}


典型深搜,求最小跳跃次数,就从最大能跳到的地方枚举

AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=110;
char a[N];
int n,d,ans=-1;//ans记录最少需要跳几次
//当他无论如何跳不到终点时,输出-1,故我们初始ans为-1
void dfs(int x,int s)
//x表示当前在字符串下标为x的位置,s表示到此位置的跳跃次数
{
	if(x==n-1)//当跳到n-1位置时,表明搜索结束,记录答案,并返回
	{
		ans=s;//从大到小枚举,第一次深搜的结果一定是最小的
		return ;//返回到上一此递归处
	}	
	for(int i=d; i>0; i--)//从大到小枚举
	{
		int xx=x+i;//xx表示下一个位置
		if(xx>n-1||a[xx]!='1')//判断当前位置能不能走
			continue;
		dfs(xx,s+1);//可以走就继续搜索
		return ;//返回到上一次递归处//一定要有
		//没有的话,会出现多次搜索到n-1的情况,ans的最佳情况被覆盖
	}
}
int main()
{
	int i,j,k;
	scanf("%d%d",&n,&d);
	scanf("%s",a);//字符串从0到n-1
	dfs(0,0);//从0开始搜,到n-1时结束,深搜结束
	printf("%d\n",ans);
	return 0;
}

1283: [蓝桥杯2016初赛]生日蜡烛

题目描述
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?

输出格式
请填写他开始过生日party的年龄数。

思路: 计算前缀和,枚举左右端点

建议填空题直接输出答案,以防代码超时等问题导致0分

AC代码:

#include<stdio.h>
int sum[310];
int main()
{
	int i,j,k;
	//最差的情况,他在236岁时,连续过了一年的生日
	//故前缀和枚举到236即可
	for(i=1;i<=236;i++)//计算前缀和
	sum[i]=sum[i-1]+i;
	for(i=1;i<=236;i++)//左端点
	for(j=i;j<=236;j++)//右端点
	if(sum[j]-sum[i-1]==236)//左半边表示从i岁到j岁共吹灭了多少蜡烛
	{
		printf("%d\n",i);//找到即输出
		return 0;
	}
	return 0;
}

1287: [蓝桥杯2016初赛]四平方和

题目描述
四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0 2+ 02 + 12 + 22
7 = 12 + 12 + 12 + 22(^符号表示乘方的意思)
对于一个给定的正整数N,可能存在多种平方和的表示法。
要求你对4个数排序:0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

输入格式
输入存在多组测试数据,每组测试数据输入一行为一个正整数N(N<5000000)

输出格式
对于每组测试数据,要求输出4个非负整数,按从小到大排序,中间用空格分开

输入样例
5
12
773535

输出样例
0 0 1 2
0 2 2 2
1 1 267 838

思路: 最大范围5000000,在最坏的情况下,02 +02 +02 +x2 =5000000,通过计算器,我们可以得知x最大为2237,故我们只需三层for循环枚举到2237,加一层特判即可

在这里插入图片描述

AC代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int a,b,c,d,n;
	while(~scanf("%d",&n))//注意多组输入
	{
		int f=0;//需要初始化的东西放里面
		for(a=0;a<2240;a++)
		{
			for(b=a;b<2240;b++)
			{
				for(c=b;c<2240;c++)//三层枚举
				{//判断余下的那个数是否可以完全int型的开方
					int x=n-a*a-b*b-c*c;//x为余下的那个数
					int dd=(int)sqrt(x);//开方
					if(dd*dd==x)//相等表明x开出来的数是int型
					{
						f=1;
						printf("%d %d %d %d\n",a,b,c,dd);
						break;
					}
				}
				if(f)
				break;
			}
			if(f)
			break;
		}
	}
	return 0;
}

1292: [蓝桥杯2016初赛]交换瓶子

题目描述
有N个瓶子,编号 1 ~ N,放在架子上。比如有5个瓶子:2 1 3 5 4,要求每次拿起2个瓶子,交换它们的位置。经过若干次后,使得瓶子的序号为:1 2 3 4 5,对于这么简单的情况,显然,至少需要交换2次就可以复位。
如果瓶子更多呢?你可以通过编程来解决。

输入格式
输入存在多组测试数据,对于每组测试数据:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

输出格式
对于每组测试数据输出一行,包含一个正整数表示答案

输入样例
5
3 1 2 5 4
5
5 4 3 2 1

输出样例
3
2

思路: 遍历一遍,边交换边记录

AC代码:

#include<stdio.h>
#include<string.h>
int a[11000],b[11000];
int main()
{
	int n,i,j,k,t,sum=0;
	while(~scanf("%d",&n))
	{//多组输入记得清空数组和变量的初始化问题
		sum=0;
		memset(a,0,sizeof(a));//需用#include<string.h> 头文件
		memset(b,0,sizeof(b));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			b[i]=i;//记录当前位置瓶子的序号应该是多少
		}
	
	for(i=1;i<=n;i++)
	{
		if(a[i]!=b[i])//不相等说明需要交换
		{
			for(j=1;j<=n;j++)//循环找到需要交换的那个数
			{
				if(b[i]==a[j])//交换并记录次数
				{
					t=a[i];
					a[i]=a[j];
					a[j]=t;
					sum++;
				 } 
			}
			
		}
	 } 
	 printf("%d\n",sum);
	}
	
	 return 0;
}

思路同上的另一种写法

AC代码:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<string.h>
using namespace std;
#define inf 0x3f3f3f3f

int a[10010];

int main()
{
    int n;
    while (cin >> n)
    {
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        int w = 0;
        for(int i = 1; i <= n; i++)
        {
            while (a[i] != i)
            {
                swap(a[i], a[a[i]]);//a[i]应在a[a[i]]位置上
                w++;
            }
        }
        cout << w << endl;
    }
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值