算法竞赛入门【码蹄集进阶塔335题】(MT2301-2305)
文章目录
前言
为什么突然想学算法了?
> 用较为“官方”的语言讲,是因为算法对计算机科学的所有分支都非常重要。 在绝大多数的计算机科学分支领域中,要想完成任何实质性的工作,理解算法的基础知识并掌握与算法密切相关的数据结构知识是必不可少的。
> 但从实际而言,是因为当下快到了考研和找工作的年纪(ಥ_ಥ),无论走哪一条路,都不免需要一些相对丰富的算法知识,是故,便产生了一个暑假速成算法的计划,可能对于像我这种算法竞赛小白而言,几乎很难,但我仍然还是想尝试一下,毕竟,梦想还是要有的,万一实现了呢?~( ̄▽ ̄~)~
为什么选择码蹄集作为刷题软件?
码蹄集,是在全国高等学校计算机教学与产业实践资源建设专家委员会(TIPCC) 指导下建设的,其依托全国各大名校计算机系和清华大学出版社等单位的强大资源,旨在为计算机学习爱好者提供全面和权威的计算机习题。
目录
1. MT2301 47论
(1)题目描述
小码哥数是只含有4,7,且4的位数等于7的位数的数字。
请你寻找大于等于n( 1≤n ≤1000000000)的最小小码哥数。
格式
输入格式:
输入包含一个整数n(1≤n ≤109)。
.
输出格式: 输出大于等于n的最小小码哥数。
样例1
输入格式: 4500
.
输出格式: 4747
(2)参考代码
#include<bits/stdc++.h>
using namespace std;
set<long long int> s;
void dfs(int four,int seven,long long int num){
if(four==seven) s.insert(num);
if(four==0&&seven==0) return;
if(seven>=1){
dfs(four,seven-1,num*10+7);
}
if(four>=1){
dfs(four-1,seven,num*10+4);
}
}
int main( )
{
long long int n;
cin>>n;
for(int i=1;i<=5;i++) dfs(i,i,0);
for(long long int i:s){
if(i>=n){
cout<<i;
break;
}
}
return 0;
}
2. MT2302 数的增殖
(1)题目描述
给定一个数n (n <1000),可以按以下方法进行增殖:1.取原数最高位,在左边加上不大于最高位一半的数,2.不作处理,现在问最多能生成多少个不同的数。
格式
输入格式:
第1行包含一个正整数n。
.
输出格式: 一个正整数,输出最多生成的数的个数。
样例1
输入: 5
.
输出: 4
(2)参考代码
import time
from typing import List,Tuple
from collections import deque,Counter
from queue import PriorityQueue
import math
from functools import lru_cache
import random
import copy
import sys
sys.setrecursionlimit(99999999)
def main():
x = int(input()[0])
@lru_cache(typed=False,maxsize=128000000)
def dp(val):
if val == 1:
return 1
tot=1
for v in range(1,(val>>1)+1):
tot += dp(v)
return tot
print(dp(x))
if __name__ == '__main__':
main();
3. MT2303 传染病
(1)题目描述
小码哥正在研究传染病的相关知识,现在遇到了这么一个问题:有一个长为n,宽为m,高为k(层数)的长方体,它可以看成n x mxk个1×1×1大小的单位正方体。每个单位正方体都有一个字符。””表示该位置防疫措施不好,如果被传染了就会感染病毒。”#”表示该区人民防疫措施良好,永远不会感染病毒(甚至都不会成为病毒的携带者)。
现在在长方体的最顶层(层号为1)某个位置,因实验室泄露爆发了病毒。每过一个单位时间,病毒将扩散至周围6个方向的地区。如果某个地区为”#”,那么一定不会被感染并且不会携带病毒同时也不会传播病毒。(但如果这个地方存在泄露的实验室,那么哪怕防疫措施再好也会被感染以及传播病毒)﹒
现在小码哥需要知道,假如第一层坐标为(a, y)的实验室泄露了病毒,那么最多会有多少区域被感染。
格式
输入格式:
第一行三个正整数k,n,m ( k, n, m ≤ 10 ) ,接下来k层,每层n行,每行m个字符,表示长方体每个单位的状态,最后一行两个正整数x,y ( a ≤n, y ≤m )表示发生泄漏的实验室的坐标(这个实验室在第一层)。
.
输出格式: 按题目要求输出一行一个整数表示答案。
样例1
输入格式:
3 3 3.#.
.###
##..##
##.
… … …
1 1
.
输出格式: 13
(2)参考代码
#include<iostream>
using namespace std;
char li[11][11][11];
int Count = 0;
int countMax = 0;
int n, m, k;
void ganran(int x, int y, int z)
{
Count++;
li[x][y][z] = '*';
if (x - 1 > 0 && li[x - 1][y][z] == '.')//向左感染
ganran(x - 1, y, z);
if (x + 1 <= n && li[x + 1][y][z] == '.')//向右感染
ganran(x + 1, y, z);
if (y - 1 > 0 && li[x][y - 1][z] == '.')//向后感染
ganran(x, y - 1, z);
if (y + 1 <= m && li[x][y + 1][z] == '.')//向前感染
ganran(x, y + 1, z);
if (z - 1 > 0 && li[x][y][z - 1] == '.')//向上感染
ganran(x, y, z - 1);
if (z + 1 <= k && li[x][y][z + 1] == '.')//向下感染
ganran(x, y, z + 1);
}
int main()
{
cin >> k >> n >> m;
for (int _k = 1;_k <= k;_k++)
for (int _n = 1;_n <= n;_n++)
for (int _m = 1;_m <= m;_m++)
cin >> li[_n][_m][_k];
int sx, sy;
cin >> sx >> sy;
ganran(sx, sy, 1);
cout << Count;
return 0;
}
4. MT2304 magic
(1)题目描述
魔法阵是一个n x m的格子(高n,宽m ) , n x m为偶数。小码哥手中有n x m个宝石(以1 ~ n x m编号)。小码哥从最右上角的格子开始走,从一个格子可以走到上、下、左、右4个相邻的格子,但不能走出边界。每个格子必须且仅能到过1次,这样小码哥一共走了n x m个格子停止(随便停哪里)。小码哥每进入一个格子,就在该格子里放入一颗宝石。他是按顺序放的,也就是说——第i个进入的格子放入à号宝石。
如果两颗宝石的编号对nx m÷2取模的值相同,则认为这两颗宝石相互之间有微妙的影响。也就是说,我们按照宝石的编号对n x m÷2取模的值,将宝石分成nx m÷2对,其中每对都恰有两颗宝石。对于每一对宝石,设第一颗宝石在第α行第b列,另一颗宝石在第c行第d列,那么定义这2个宝石的魔力影响值为x |a 一 c| +k× (b- d。需要你求出的是,在所有合乎题意的宝石摆放方案中,所有成对的宝石间的最大魔力影响值的最小值为多少。换句话说,如果我们定义对n x m÷2取模的值为i的一对宝石的魔力影响值为a[团]。你需要求出的就是maa { a[i][i= 0,1,2…}的最小值。
格式
输入格式:
只有一行用空格隔开的4个正整数,分别是n、m、k1、k2。(4≤n ×m≤50,0<k1,k2≤32767) 。
.
输出格式: 只需输出一个整数,即题目所要求的“所有成对的宝石间的最大魔力影响值的最小值”。
样例1:
输入: 2 2 2 2
输出:4
(2)参考代码
#include<bits/stdc++.h>
using namespace std;
int t,n,m,k1,k2,ans=0x3f3f3f3f;
int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};//四个方向
int num[60][2];//用于第一次记录,下面会提
bool vis[60][60];//标记走过没
inline void dfs(int x,int y,int sum,int maxn)//x表示当前x坐标,y表示当前y坐标,sum表示当前步数,maxn表示当前最大值
{
if(vis[x-1][y]&&vis[x+1][y]&&!vis[x][y+1]&&!vis[x][y-1])return;//可行性剪枝1
if(vis[x][y-1]&&vis[x][y+1]&&!vis[x+1][y]&&!vis[x-1][y])return;//可行性剪枝2
if(sum<=t)num[sum][0]=x,num[sum][1]=y;//记录,这里t指一半
else
{
maxn=max(maxn,k1*abs(num[sum-t][0]-x)+k2*abs(num[sum-t][1]-y));//进行计算并更新
//return;
}
if(sum>=n*m)
{
ans=min(ans,maxn);//如果遍历完,那么更新答案
return;
}
if(maxn>=ans)return;//最优性剪枝
for(int i=1;i<=4;i++)//四个方向枚举
{
int a=x+dx[i],b=y+dy[i];
if(!vis[a][b])
{
vis[a][b]=1;
dfs(a,b,sum+1,maxn);
vis[a][b]=0;//回溯
}
}
}
int main()
{
cin>>n>>m>>k1>>k2;
t=n*m/2;
for(int i=0;i<=m+1;i++)
{
vis[0][i]=1;
vis[n+1][i]=1;
}//在外围加个边框1
for(int i=0;i<=n+1;i++)
{
vis[i][0]=1;
vis[i][m+1]=1;
}//在外围加个边框2
vis[1][1]=1;//初始标记
dfs(1,1,1,0);
cout<<ans<<endl;
return 0;
}
5. MT2305 集装箱
(1)题目描述
码头上的工人们在给出口的菠萝装船,船有两艘,从键盘输入它们的载重α和b。菠萝分装在k个集装箱里面,k和每个集装箱的重量从键盘输入,请判断工人们是否能够成功将这些菠萝装船(集装箱不可拆分)。
格式
输入格式:
依次输入a,b,k以及k个集装箱的重量,空格分隔,1≤a,b ≤5000,2 ≤k ≤10,0≤每个集装箱的重量≤3500。
.
输出格式: 可将装船则输出yes ,否则输出no 。
样例1
输入格式: 54 100 5 26 50 30 23 25
.
输出格式: no
(2)参考代码
#include<bits/stdc++.h>
using namespace std;
int c1,c2,n;
int boxw[10];
int sum=0;
int bestC1;
int weight_cur;
void backtrack(int a){
if(a==n){
if(weight_cur>bestC1)
bestC1 = weight_cur;
return;
}
if(weight_cur+boxw[a] <= c1){
weight_cur+= boxw[a];
backtrack(a+1);
weight_cur-= boxw[a];
}
backtrack(a+1);
}
int main( )
{
cin>>c1>>c2>>n;
for(int i=0;i<n;i++){
cin>>boxw[i];
sum+=boxw[i];
}
bestC1 = weight_cur = 0;
backtrack(0);
if(sum-bestC1 <= c2){
cout<<"yes"<<endl;
}else{
cout<<"no"<<endl;
} return 0;
}
结语
感谢大家一直以来的不断支持与鼓励,码题集题库中的进阶塔350题正在逐步更新,之后会逐步跟进星耀,王者的题,尽请期待!!!
同时,也希望这些题能帮助到大家,一起进步,祝愿每一个算法道路上的“苦行僧”们,都能够历经磨难,终成正果,既然选择了这条路,走到了这里,中途放弃,岂不是太过可惜?
另附中国计算机学会的杰出会员、常务理事轩哥博士的B站视频讲解链接https://space.bilibili.com/518554541/?spm_id_from=333.999.0.0,供大家更好的进行学习与刷题~( ̄▽ ̄~)~
愿你的结局,配得上你一路的颠沛流离。