蓝桥杯15届B组题解

蓝桥杯15届B组题解(二)

数字接龙

题目描述

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × N 的格子棋盘上展开,其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下:

\1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。

\2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。

\3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。

\4. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。

为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图2 所示;因此行进路径可以用一个包含 0 . . . 7 之间的数字字符串表示,如下图 1是一个迷宫示例,它所对应的答案就是:41255214。

蓝桥杯2024年第十五届省赛真题-数字接龙

现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 −1。

输入格式

第一行包含两个整数 N、K。接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。

输出格式

输出一行表示答案。如果存在答案输出路径,否则输出 −1。

样例输入
3 3
0 2 0
1 1 1
2 0 2
样例输出
41255214
提示

【样例说明】行进路径如图 1 所示。
【评测用例规模与约定】对于 80% 的评测用例:1 ≤ N ≤ 5。对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

解题思路

难点在于,如何处理交叉问题。

用深度搜索的话

假如某个点要到【-1,-1】左上的点,只需要检查【-1,0】【0,-1】是否走过即可。其他的右上,右下,左下,以此类推。

当走时,优先选择字典序小的方向,及从0,1,2,3一直到7。深度搜索时,从字典序小的方向依次探测到字典序大的方向。

#include<bits/stdc++.h> 
using namespace std;

const int N =10+2; 
int g[N][N]; 
int vis[N][N];
int n;
int k;
int dx[]={-1,-1,0,1,1,1,0,-1};
int dy[]={0,1,1,1,0,-1,-1,-1};
int tt;
bool finds=false;
void dfs(int x,int y,vector<char>& s,int pt)
{
	if(finds)return;
	vis[x][y]=1;
	if(x==n&&y==n) 
	{
        //第一个找到满足条件的路径,就是所求路径。
		if(s.size()==n*n-1) 
		{
			for(auto c:s) 
				cout<<c;
			finds =true;
		}
		vis[x][y]=0;
		return; 
	}
	if(x<1||y<1||x>n||y>n)
		 return;
	for(register int i=0;i<8;i++)
	{
		int ct = abs(dx[i])+abs(dy[i]);
		int tx = dx[i]+x;
		int ty = dy[i]+y;
		if(g[tx][ty]!=(pt+1)%k)
		{
			continue;
		}
		if(ct>1&&vis[tx][y]&&vis[x][ty]||vis[tx][ty]) 
			continue;

		char c = ('0'+i);
		s.push_back(c);
		dfs(tx,ty,s,(pt+1)%k);
		s.pop_back();	
	}

	vis[x][y]=0;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k; 
    //判断特殊情况
	if(n==1)
	{
		cout<<"-1";
		return 0;
	}
	for(register int i=1;i<=n;i++)for(register int j=1;j<=n;j++)cin>>g[i][j];
	vector<char >c;
	dfs(1,1,c,0);
	if(!finds) cout<<"-1";
}

爬山

题目描述

小明这天在参加公司团建,团建项目是爬山。在 x 轴上从左到右一共有 n座山,第 i 座山的高度为 hi。他们需要从左到右依次爬过所有的山,需要花费的体力值为 S = Σni=1hi。

然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为 H 的山的高度变为 ⌊√H⌋,可以使用 P 次;第二种魔法可以将高度为 H 的山的高度变为 ⌊H/2⌋,可以使用 Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。

小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?

输入格式

输入共两行。

第一行为三个整数 n,P,Q。

第二行为 n 个整数 h1,h2,. . . ,hn。

输出格式

输出共一行,一个整数代表答案。

样例输入
4 1 1
4 5 6 49
样例输出
18
提示

【样例说明】将第四座山变为 ⌊√49⌋ = 7,然后再将第四座山变为 ⌊7/2⌋ = 3。体力值为 4 + 5 + 6 + 3 = 18。

【评测用例规模与约定】

对于 20% 的评测用例,保证 n ≤ 8,P = 0。

对于 100% 的评测用例,保证 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ hi ≤ 100000。

解题思路

为了保证更好的节省体力,优先对大的数进行调整。
⌊ 1 1 / 2 ⌋ = 1 , ⌊ 1 / 2 ⌋ = 0 ⌊ 2 1 / 2 ⌋ = 1 , ⌊ 2 / 2 ⌋ = 1 ⌊ 3 1 / 2 ⌋ = 1 , ⌊ 3 / 2 ⌋ = 1 ⌊ 4 1 / 2 ⌋ = 2 , ⌊ 4 / 2 ⌋ = 2 ⌊ 5 1 / 2 ⌋ = 2 , ⌊ 5 / 2 ⌋ = 2 . . . . ⌊ 9 1 / 2 ⌋ = 3 , ⌊ 9 / 2 ⌋ = 4 \lfloor 1^{1/2} \rfloor=1,\lfloor 1/2 \rfloor =0\\ \lfloor 2^{1/2} \rfloor=1,\lfloor 2/2 \rfloor =1\\ \lfloor 3^{1/2} \rfloor=1,\lfloor 3/2 \rfloor =1\\ \lfloor 4^{1/2} \rfloor=2,\lfloor 4/2 \rfloor =2\\ \lfloor 5^{1/2} \rfloor=2,\lfloor 5/2 \rfloor =2\\ ....\\ \lfloor 9^{1/2} \rfloor=3,\lfloor 9/2 \rfloor =4\\ 11/2=1,1/2=021/2=1,2/2=131/2=1,3/2=141/2=2,4/2=251/2=2,5/2=2....91/2=3,9/2=4
根据推理,需要将最大的数,进行这两种操作后选最小的

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, P, Q;
    long long ans = 0;
    priority_queue<int> h;
    cin >> n >> P >> Q;
    for (int i = 0; i < n; i++)
    {
        int hi;
        cin >> hi;
        h.push(hi);
    }
    while (P || Q)
    {

        int first = h.top();
        h.pop();
        if (P && Q)
        {
        	//如果要单纯的把测试用例全部过了 
//        	if(P==1&Q==1&&h.size()==1)
//        	{
//        		int t2 = h.top();
//        		h.pop();	
//        		int res1 = (int)sqrt(first)+t2/2;
//        		int res2 = (int)sqrt(t2)+first/2;
//        		h.push(min(res1,res2));
//        		Q--,P--;
//        		break; 
//			}
//			
            if (sqrt(first) <= first / 2)
            {
                h.push(sqrt(first));
                P--;
            }
            else
            {
                h.push(first / 2);
                Q--;
            }
        }
        //如果只剩一种魔法了,就直接用
        else if (P)
        {
            h.push(sqrt(first));
            P--;
        }
        else if (Q)
        {
            h.push(first / 2);
            Q--;
        }
    }
    while (!h.empty())
    {
        ans += h.top();
        h.pop();
    }
    cout << ans;
    return 0;
}

不过本题分拿不满, 因为有特例情况。例如其中之一

2 1 1

48 49

正确答案是30,实则按代码跑出来31

{
h.push(first / 2);
Q–;
}
}
while (!h.empty())
{
ans += h.top();
h.pop();
}
cout << ans;
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值