2022蓝桥杯C++B组国赛真题题解(二)

简介: 2022蓝桥杯C++B组国赛真题题解

E:出差


问题描述

A 国有 N 个城市, 编号为 1…N 。小明是编号为 1 的城市中一家公司的员 工, 今天突然接到了上级通知需要去编号为 N 的城市出差。


由于疫情原因, 很多直达的交通方式暂时关闭, 小明无法乘坐飞机直接从 城市 1 到达城市 N, 需要通过其他城市进行陆路交通中转。小明通过交通信息 网, 查询到了 M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的 时间。


同样由于疫情原因, 小明到达一个城市后需要隔离观察一段时间才能离开 该城市前往其他城市。通过网络, 小明也查询到了各个城市的隔离信息。(由于 小明之前在城市 1 , 因此可以直接离开城市 1 , 不需要隔离)


由于上级要求, 小明希望能够尽快赶到城市 N, 因此他求助于你, 希望你 能帮他规划一条路线, 能够在最短时间内到达城市 N 。


输入格式

第 1 行: 两个正整数N,M,N 表示 A 国的城市数量, M 表示末关闭的路 线数量


第 2 行: N 个正整数, 第 i 个整数 Ci 表示到达编号为i 的城市后需要隔离 的时间


第 3 …M+2 行: 每行 3 个正整数,u,v,c, 表示有一条城市 uu 到城市 v的 双向路线仍然开通着, 通过该路线的时间为 c


输出格式

第 1 行: 1 个正整数, 表示小明从城市 1 出发到达城市 N 的最短时间(到 达城市 N, 不需要计算城市 N 的隔离时间)


样例输入

4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5

样例输出

13

样例说明

评测用例规模与约定

对于 100% 的数据, 1≤N≤1000,1≤M≤10000,1≤Ci≤200,1≤u,v≤ N,,1≤c≤1000


运行限制

最大运行时间:1s

最大运行内存: 512M

最短路径采用Dijkstra算法会快一点;

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int n,m;     //n个城市,m条路线 
int geli[10005];   //到每个城市的隔离时间 
int luxian[10005][10005];
int juli[10005];          //到一点的最短距离 
bool vis[10005];
int dj(){
  memset(juli,0x3f3f3f3f,sizeof(juli));
  juli[1]=0;      //距离起点为0 
  geli[1]=0;      //出自己城市不隔离 
  geli[n]=0;      //到达终点不需要隔离 
  for(int i=1;i<=n;i++){   //剔除n个
    int s=-1;
    for(int j=1;j<=n;j++){
      if(!vis[j]&&((s==-1)||(juli[j]<juli[s]))){
        s=j;   //第一次s为1,之后每一次寻找与前一个想通的城市
      }
    } 
    vis[s]=1;
    for(int j=1;j<=n;j++){
      juli[j]=min(juli[j],juli[s]+luxian[s][j]+geli[s]);
    }
  }
  return juli[n];
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++){
    cin>>geli[i];
  }
  memset(luxian,0x3f3f3f3f,sizeof(luxian));  //无穷大
  for(int i=1;i<=n;i++){
    luxian[i][i]=0;                    //自己到自己为0 
  } 
  for(int i=0;i<m;i++){
    int a,b,c;
    cin>>a>>b>>c;
    luxian[a][b]=luxian[b][a]=min(c,luxian[a][b]);
  }
  int ans=dj(); 
  cout<<ans; 
  return 0;
}

F:费用报销


问题描述

小明在出差结束后返回了公司所在的城市, 在填写差旅报销申请时, 粗心 的小明发现自己弄丢了出差过程中的票据。


为了弥补小明的损失, 公司同意小明用别的票据进行报销, 但是公司财务 要求小明提交的票据中任意两张的日期差不小于 K 天, 且总金额不得超过实际 差旅费用 M 。


比如财务要求 K=7 时, 若小明提交了一张 1 月 8 日的票据, 小明就不能 提交 1 月 2 日至 1 月 14 日之间的其他票据, 1 月 1 日及之前和 1 月 15 日及之 后的票据则可以提交。


公司的同事们一起给小明凑了 N 张票据, 小明现在想要请你帮他整理一 下, 从中选取出符合财务要求的票据, 并使总金额尽可能接近 M 。


需要注意, 由于这些票据都是同一年的, 因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。


输入格式

第 1 行: 3 个整数, N,M,K


第 2…N+1 行: 每行 3 个整数 mi,di,vi, 第 i+1 行表示第 i 张票据时间 的月份 mi 和日期 di,vi 表示该票据的面值


输出格式

第 1 行: 1 个整数, 表示小明能够凑出的最大报销金额


样例输入

4 16 3
1 1 1
1 3 2
1 4 4
1 6 8

样例输出

10

样例说明

选择 1 月 3 日和 1 月 6 日的票据


评测用例规模与约定

对于 100% 的评测用例, 1≤N≤1000,1≤M≤5000,1≤K≤50,1≤mi≤ 12,,1≤di≤31,1≤vi≤400


日期保证合法。


运行限制

最大运行时间:1s

最大运行内存: 512M

动态规划问题, 先将n张票据以结构体保存下来,然后转化为数组,但是一天可能有好几张票据,因此我们要将一天票据进行比较。然后利用递推公式:


选i票据:ans[i]           ans[i-k]+面值[i]      前提小于等于m'


不选i票据:ans[i]       ans[i-1]


因此:ans[i]=max(ans[i-k]+面值[i],ans[i-1])


然后就是在于一天中每个票据挨个比较

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int n,m,k;     //n代表n个票据,m钱,k天
int piao1[400];
int ans[500];
vector<int> piao2[400];
int month12[12]={31,28,31,30,31,30,31,31,30,31,30,31};
struct piao{
  int month;
  int day;
  int qian;
}; 
piao a[1005];
int getday(int x,int y){
  int ans=y;
  for(int i=0;i<x-1;i++){
    ans+=month12[i];
  }
  return ans;
}
int main(){
  cin>>n>>m>>k;
  for(int i=1;i<=n;i++){
    cin>>a[i].month>>a[i].day>>a[i].qian;
  }    //输入结构体 
  int daymax=0;
  for(int i=1;i<=n;i++){
    int day=getday(a[i].month,a[i].day);
    if(piao1[day]){
      piao2[day].push_back(a[i].qian);
    }else{
      piao1[day]=a[i].qian;
    }
    daymax=max(day,daymax);                          //全转为天数,重合的装在vector里 
  } 
  for(int i=1;i<=daymax;i++){       //遍历每天的票据 
    if(piao1[i]==0) {
      ans[i]=ans[i-1];      //这一天没有票,等于上一天的值 
    }else{
      if(piao2[i].size()==0){  //这一天只有一张票 
        if(ans[i-1]<=m){
          ans[i]=ans[i-1];
        } 
        if(ans[i-k]+piao1[i]<=m){
          ans[i]=max(ans[i],ans[i-k]+piao1[i]);
        }
      }else{
        if(ans[i-1]<=m){
          ans[i]=ans[i-1];     //这一天有多张票 
        } 
        if(ans[i-k]+piao1[i]<=m){
          ans[i]=max(ans[i],ans[i-k]+piao1[i]);
        }
        int len=piao2[i].size();
        for(int j=0;j<len;j++){
          if(ans[i-k]+piao2[i][j]<=m){
            ans[i]=max(ans[i],ans[i-k]+piao2[i][j]);
          }
        }
      }
    } 
  } 
  cout<<ans[daymax];
  return 0;
}

G:故障


问题描述

在软件或系统开发中, 我们会遇到各种各样的故障。为了从故障现象反推 故障原因, 工程师们会总结一种叫做相关性矩阵的二维表格, 来表示故障原因 与故障现象之间的关系。比如:

其中每行表示一种故障原因, 每一列表示一种故障现象。该矩阵表示故障 原因 AA 可能产生故障现象 2、3、4, 故障原因 BB 可能产生故障现象 1、3。


在实际开发过程中, 如果出现了故障原因, 工程师就可以根据故障现象, 去计算每种故障原因产生的概率, 并按照概率大小对故障原因进行排查, 以达 到快速定位故障原因的目的。


现在, 我们假设系统开发中同一时间只会出现一种故障原因, 并且故障原 因引起各故障现象是独立事件。举个例子来说:


假设系统现在发生了故障原因 A, 有 1/3的概率出现故障现象 2 , 有 1/4 的概 率出现故障现象 3 , 有 1/2的概率出现故障现象 4。由于 3 种现象是独立发生的, 因此有 1/3*1/4*1/2 的概率同时出现故障 2、3、4。


约定若相关性矩阵中没有 ' x ' 记号, 则表示该故障原因一定不会产生某故 障现象, 比如故障原因 A, 一定不会产生故障现象 1。


根据历史经验数据, 我们统计得到了每一种故障原因出现的概率以及每一 种故障原因对应的故障现象产生概率。


现在已知系统出现的故障现象, 求问各个故障原因发生的概率。


输入格式

第 1 行: 2 个正整数 N,M,N 表示故障原因的个数(编号 1…N ), M 表 示故障现象的个数 (编号 1 1…M)


第 2 行: N 个整数, 第 i 个数表示故障原因 i 产生的概率 Pi.


第 3…N+2 行: 每行 M 个整数, 第 i+2 行第 j 个整数 Pij 表示故障原 因 i 出现故障现象 j 的概率 (百分比).


第 N+3 行: 1 个正整数 K, 表示目前出现的故障现象数量


第 N+4 行: K 个正整数, 依次为当前出现的故障现象编号, 不会重复


输出格式

第 1…N 行: 按概率从高到低输出每种故障原因及其可能的概率, 若出现 概率相同则优先输出编号小的故障原因。第 1 个数为故障原因编号, 第 2 个数 为故障概率 (百分比), 保留 2 位小数。


样例输入

3 5
30 20 50
0 50 33 25 0
30 0 35 0 0
0 0 0 25 60
1
3

样例输出

2 56.89
1 43.11
3 0.00

评测用例规模与约定

对于所有测试用例, 1≤N≤40,1≤M≤20,0≤Pi≤100,Σ(Pi)=100, 0≤Pij≤100,


运行限制

最大运行时间:1s

最大运行内存: 512M

这个题敢不敢再写得长一点,看题目半小时过去了,概率题;

就是这个算法,概率论的题,还好我们开过这门课,呜呜呜呜呜。

#include <iostream>
#include <stdio.h>
#include <algorithm> 
#include <cmath>
using namespace std;
int n,m;       //n行,m列 
int yuanyin[450];
int p1[450][450];
int k;
int guzhang[4500];
int vis2[450];
int vis1[450];
double dange[450]; 
int id[450];
bool cmp(int a,int b){
  if(fabs(dange[a]-dange[b])>1e-8){
    return dange[a]>dange[b];     //当不相等时返回大的,否则返回id值小的
  }else{
    return a<b;
  }
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++){
    cin>>yuanyin[i];
  }
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      cin>>p1[i][j];
    }
  }
  cin>>k;
  for(int i=1;i<=k;i++){
    cin>>guzhang[i];
    vis1[guzhang[i]]=1;          //标记故障 
  }
  double num=0;
  for(int i=1;i<=n;i++){
    dange[i]=1;         //便于乘 
    for(int j=1;j<=m;j++){
      if(vis1[j]){   //此点是故障点 
        dange[i]=(double)dange[i]*p1[i][j]/100.0;   
      }else{
        dange[i]=(double)dange[i]*(100-p1[i][j])/100.0;
      } 
    }
    dange[i]=(double)dange[i]*yuanyin[i]/100.0;
    num+=dange[i];  
  }
  if(fabs(num)<1e-9){
    for(int i = 1 ; i <= n ; i ++){
      printf("%lld 0.00\n" , i) ;
    }
    return 0 ;
  }
  for(int i=1;i<=n;i++){      //很巧妙的排序,对id排序,然后输出
    id[i]=i;
    dange[i]=dange[i]*100.0/num;
  }
  sort(id+1,id+1+n,cmp);   //根据dange的值排id
  for(int i=1;i<=n;i++){
    printf("%lld %0.2lf\n",id[i],dange[id[i]]);
  } 
  return 0;
}
相关文章
|
2月前
|
存储 机器学习/深度学习 算法
第十五届蓝桥杯pb组国赛E题[马与象] (15分)BFS算法 详解
第十五届蓝桥杯pb组国赛E题[马与象] (15分)BFS算法 详解
26 3
|
2月前
|
存储 算法 测试技术
第十五届蓝桥杯大赛 国赛 pb组F题【括号与字母】(15分) 栈的应用
第十五届蓝桥杯大赛 国赛 pb组F题【括号与字母】(15分) 栈的应用
17 1
|
2月前
|
Java
2016届蓝桥杯大赛软件类国赛Java大学B组 愤怒小鸟 数学模拟
2016届蓝桥杯大赛软件类国赛Java大学B组 愤怒小鸟 数学模拟
37 4
|
2月前
|
Java
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针
27 3
|
2月前
|
Java
2021蓝桥杯大赛软件类国赛Java大学B组 完全日期 复杂遍历搜索
2021蓝桥杯大赛软件类国赛Java大学B组 完全日期 复杂遍历搜索
31 2
|
2月前
|
Java
2023届蓝桥杯大赛软件类国赛Java大学B组 互质 数论
2023届蓝桥杯大赛软件类国赛Java大学B组 互质 数论
18 1
|
2月前
|
存储 索引
6/1 第十五届蓝桥杯国赛pb组 真题本人答案 仅供参考
6/1 第十五届蓝桥杯国赛pb组 真题本人答案 仅供参考
31 4
|
3月前
|
算法 测试技术 C++
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
|
3月前
|
算法 C++ 数据格式
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
|
2月前
|
存储 前端开发 算法
2016届蓝桥杯大赛软件类国赛Java大学B组 反幻方 暴力搜索
2016届蓝桥杯大赛软件类国赛Java大学B组 反幻方 暴力搜索
19 0