一条咸鱼试图骗分的故事

本文通过一个生动的故事介绍了乌龟棋游戏的规则,玩家需利用不同步数的卡片从起点走到终点,途中收集格子上的分数。作者分享了两次尝试解题的骗分思路,最终通过动态规划的方法找到了正确解答。代码实现中,使用四维数组记录不同步数卡片剩余数量下的最大得分,通过状态转移方程求解,得到了计算最高得分的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

乌龟棋tortoise

  • ——一道让人下意识开始骗分的题**

一个来自万年吃饱了撑的、没事闲得慌的、遇事绝对只会找人帮忙的、一旦自己解决问题绝对会出错的小明的故事_(¦3)∠)_

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行 N 个格子,每个格子上一个分数(非负整数)。棋盘第1 格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中 M 张爬行卡片,分成 4 种不同的类型(M 张卡片中不一定包含所有 4 种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。
游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

**

去掉废话以后,这道题是这样滴(ノ`Д)ノ

在这里插入图片描述

每个格子内有不同的分值,从起点开始,每个被走过的格子(包括起点)的分值累加起来,就是总分。有一步、两步、三步、四步、四种走法,每种走法使用次数有限制。问如何走让总分最大 (_ _)( - . - )(O)……( - . - )

**

Input
输入文件的每行中两个数之间用一个空格隔开。
第 1 行 2 个正整数 N 和 M,分别表示棋盘格子数和爬行卡片数。
第 2 行 N 个非负整数,a1,a2,……,aN,其中 ai 表示棋盘第i个格子上的分数。
第 3 行 M 个整数,b1,b2, ……, bM,表示 M 张爬行卡片上的数字。
输入数据保证到达终点时刚好用光 M 张爬行卡片。
Output
输出只有1 行,1 个整数,表示小明最多能得到的分数

Constraints
• 对于30%的数据有1 ≤ N≤ 30,1 ≤M≤ 12。
• 对于50%的数据有1 ≤ N≤ 120,1 ≤M≤ 50,且4 种爬行卡片,每种卡片的张数不会超过20。
• 对于100%的数据有1 ≤ N≤ 350,1 ≤M≤ 120,且4 种爬行卡片,每种卡片的张数不会超过40;0 ≤ ai ≤ 100, 1 ≤ i ≤ N;1 ≤ bi ≤ 4,1 ≤ i ≤M。

审题完毕(o)/~
因为要求写得很清楚就不看样例了
(ˉ▽ ̄~) ~

不管如何当时的自己是很愉快地跳坑了 ε=(´`ο`*)))

(以下是跳坑路程(づ ̄3 ̄)づ)

首先把基本的框架打好~
输入输出什么的
(没错此时已经愉快地跌进坑里了(o)/~)

使用了一个b的数组记录卡片

	for(int i=1;i<=m;i++)
	{
		b[i]=Read();
	}

(Read是快读函数(*^▽ ^ *))

接着陷入了苦思冥想中…

然后灵机一动(キ`゚Д゚´)!!

一个愉快的骗分代码迅速地成型了O(∩_∩)O

把a数组(每个格子里的分值)sort一遍,把最后m(卡片数量)个(也就是分值最大的m个)加起来,然后输出()

很快地走了一遍样例后发现两个样例过了一个(⊙o⊙)…!!

于是带着期待带着向往带着希望带着憧憬……把这份代码扔上去过老师给的十个数据…

很意外的全错了_(¦3)∠)_

于是只好继续苦思冥想o(╥﹏╥)o…

屈指西风几时来~只恐流年暗中换 ~

第二个骗分代码忽然成型(o)/~

从最后一格开始,把每个卡牌试一遍然后选择能走到的最大格,把这张卡牌标记掉,把起点换成当前格接着走~走到起点为止,一路把分值记录下来 (〃’▽’〃)

小心翼翼…啊不 一鼓作气地过了样例
意料之中(并没有)地全对!

于是带着期待带着向往带着希望带着憧憬……把这份代码扔上去过老师给的十个数据…

十个对了两个(⊙o⊙)…

非常满足()!!!

然后就闲鱼躺了,人生已经很美好了,能对两个已经很惊喜了,行止辄自由甚觉身潇洒知足常乐哦吼吼吼o( ̄▽ ̄)o

本来应该从此刻起愉快地呆在坑里不出来的
(^U^)ノ~
但此时大佬突然出现——!一口气过了所有数据Σ(⊙▽⊙”
于是受到激励的某咸鱼默默回去开始重新审题

很遗憾,碧落黄泉为奴寻遍 ~ 可只有骗分思路~至于真正的解题思路……
两处茫茫皆不见(´っω•`。)

于是某咸鱼重新躺平,静等大佬讲解_(¦3)∠)_

光阴~ 如骏马加鞭~~ 浮世 ~ 似落花流水~

转眼大佬开始讲解,首先展示了其代码

#include<cmath>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a[400],b[150],f[50][50][50][50],card[6],ans;
int main()
{
	freopen("tortoise.in","r",stdin);
	freopen("tortoise.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
	{
		int x;
		scanf("%d",&x);
		card[x]++;
	}
	f[0][0][0][0]=a[1];
	for(int q=0;q<=card[1];q++)
	    for(int w=0;w<=card[2];w++)
	        for(int e=0;e<=card[3];e++)
	            for(int r=0;r<=card[4];r++)
	{
		if(q>=1) f[q][w][e][r]=max(f[q][w][e][r],f[q-1][w][e][r]+a[1+q+w*2+e*3+r*4]);
		if(w>=1) f[q][w][e][r]=max(f[q][w][e][r],f[q][w-1][e][r]+a[1+q+w*2+e*3+r*4]);
		if(e>=1) f[q][w][e][r]=max(f[q][w][e][r],f[q][w][e-1][r]+a[1+q+w*2+e*3+r*4]);
		if(r>=1) f[q][w][e][r]=max(f[q][w][e][r],f[q][w][e][r-1]+a[1+q+w*2+e*3+r*4]);
	}
	cout<<f[card[1]][card[2]][card[3]][card[4]]<<endl;
	return 0;
}
//f[a][b][c][d]=max(f[a-1]

受到四维数组惊吓后整个人都是晕的呃啊
此乃“超鸿蒙,混希夷,寂寥而莫我知也”
ε=(´ο`*)))

但接下来大佬讲解的思路很清晰,愉快地听懂后发现原来的思路全是错的┭┮﹏┭┮(虽然原来好像根本没有往真正解题上想o(╥﹏╥)o)
因为有四种卡片,所以制作一个四维数组
f[走一步的卡的数量][ 走两步的卡的数量][ 走三步的卡的数量][ 走四步的卡的数量]
这个数组放的是有多少什么卡的情况下能走到的最大分值

没错就是熟悉的动态规划(づ ̄3 ̄)づ╭❤~

**把状态划分好后,状态转移方程就很容易了

f[a1][a2][a3][a4]=max(f[走一步的卡少一张], f[走两步的卡少一张]
,f[走三步的卡少一张],f[走四步的卡少一张])+当前格子里的分值

顺便把b数组换成一个小小的card数组,
再输入时记录不同的卡分别有多少张**

整理一下代码就完成了(^-^)V!

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;

const long long int N= 50;
inline long long int Read();
long long int a[400],f[N][N][N][N],card[6],n,m,sum,a1;
int main()
{
    freopen("tortoise.in","r",stdin);
	freopen("tortoise.out","w",stdout);
    
	n=Read();
	m=Read();
	
	for(int i=1;i<=n;i++)
	{
		a[i]=Read();
	}
	/*
	蒹葭 
	
	蒹葭苍苍,白露为霜。所谓伊人,在水一方。
	溯洄从之,道阻且长。溯游从之,宛在水中央。
	
	蒹葭苍苍,白露未晞。所谓伊人,在水之湄。
	溯洄从之,道阻且跻。溯游从之,宛在水中坻。
	
	蒹葭苍苍,白露未已。所谓伊人,在水之涘。
	溯洄从之,道阻且右。溯游从之,宛在水中沚。 
	*/sum+=a[n];
	
	for(int i=1;i<=m;i++)
	{
		int x=Read();
		card[x]++;
	}
	
	f[0][0][0][0]=a[1];

	for(int a1=0;a1<=card[1];a1++)
	{
		for(int a2=0;a2<=card[2];a2++)
		{
			for(int a3=0;a3<=card[3];a3++)
			{
				for(int a4=0;a4<=card[4];a4++)
				{
					if(a1>=1){f[a1][a2][a3][a4]=max(f[a1][a2][a3][a4],f[a1-1][a2][a3][a4]+a[1+a1+a2*2+a3*3+a4*4]);}
					if(a2>=1){f[a1][a2][a3][a4]=max(f[a1][a2][a3][a4],f[a1][a2-1][a3][a4]+a[1+a1+a2*2+a3*3+a4*4]);}
					if(a3>=1){f[a1][a2][a3][a4]=max(f[a1][a2][a3][a4],f[a1][a2][a3-1][a4]+a[1+a1+a2*2+a3*3+a4*4]);}
					if(a4>=1){f[a1][a2][a3][a4]=max(f[a1][a2][a3][a4],f[a1][a2][a3][a4-1]+a[1+a1+a2*2+a3*3+a4*4]);}
				}
			}
		}
	}
    
    cout<<f[card[1]][card[2]][card[3]][card[4]];
    
    fclose(stdin);
	fclose(stdout);
    
    return 0;
}

inline long long int Read()
{
	long long int p = 0;
	bool isNeg = false;
	char c = getchar();
	while (!isdigit(c) && c != '-') c = getchar();
	if (c == '-') {isNeg = true; c = getchar();}
	while (isdigit(c)) {p = p * 10 + c - '0'; c = getchar();}
	return isNeg ? -p : p;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值