模拟
1.概念
所有不用正规算法解决的题目都可以称为模拟题
模拟算法其实就是根据题目的要求一步一步解决,但是要尽可能考虑到所有的情况,不能重复或遗漏,这就是模拟题唯一的难点
其他就没啥好说的了,直接上例题😎
2.例题
2.1 公交换乘
2.1.1题目
题目描述
著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案:
在搭乘一次地铁后可以获得一张优惠票,有效期为 45 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。在有效期内指开始乘公交车的时间与开始乘地铁的时间之差小于等于 45 分钟,即: tbus−tsubway≤45
搭乘地铁获得的优惠票可以累积,即可以连续搭乘若干次地铁后再连续使用优惠票搭乘公交车。
搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。
现在你得到了小轩最近的公共交通出行记录,你能帮他算算他的花费吗?
输入格式
输入文件的第一行包含一个正整数 n,代表乘车记录的数量。
接下来的 n 行,每行包含 3 个整数,相邻两数之间以一个空格分隔。第 i 行的第 1 个整数代表第 i 条记录乘坐的交通工具,0 代表地铁,1 代表公交车;第 2 个整数代表第 i 条记录乘车的票价 pricei ;第三个整数代表第 i 条记录开始乘车的时间 ti(距 0 时刻的分钟数)。
我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。
输出格式
输出文件有一行,包含一个正整数,代表小轩出行的总花费。
输入输出样例
输入 #1
6
0 10 3
1 5 46
0 12 50
1 3 96
0 5 110
1 6 135
输出 #1
36
输入 #2
6
0 5 1
0 20 16
0 7 23
1 18 31
1 4 38
1 7 68
输出 #2
32
说明/提示
【输入输出样例 1 说明】
第一条记录,在第 3 分钟花费 10 元乘坐地铁。
第二条记录,在第 46 分钟乘坐公交车,可以使用第一条记录中乘坐地铁获得的优惠票,因此没有花费。
第三条记录,在第 50 分种花费 12 元乘坐地铁。
第四条记录,在第 96 分钟乘坐公交车,由于距离第三条记录中乘坐地铁已超过 45 分钟,所以优惠票已失效,花费 3 元乘坐公交车。
第五条记录,在第 110 分钟花费 5 元乘坐地铁。
第六条记录,在第 135 分钟乘坐公交车,由于此时手中只有第五条记录中乘坐地铁获得的优惠票有效,而本次公交车的票价为 6 元,高于第五条记录中地铁的票价 5 元,所以不能使用优惠票,花费 6 元乘坐公交车。
总共花费 36 元。
【输入输出样例 2 说明】
第一条记录,在第 1 分钟花费 5 元乘坐地铁。
第二条记录,在第 16 分钟花费 20 元乘坐地铁。
第三条记录,在第 23 分钟花费 7 元乘坐地铁。
第四条记录,在第 31 分钟乘坐公交车,此时只有第二条记录中乘坐的地铁票价高于本次公交车票价,所以使用第二条记录中乘坐地铁获得的优惠票。
第五条记录,在第 38 分钟乘坐公交车,此时第一条和第三条记录中乘坐地铁获得的优惠票都可以使用,使用获得最早的优惠票,即第一条记录中乘坐地铁获得的优惠票。
第六条记录,在第 68 分钟乘坐公交车,使用第三条记录中乘坐地铁获得的优惠票。
总共花费 32 元。
【数据规模与约定】
对于 30% 的数据,n≤1000,ti≤106。
另有 15% 的数据,ti≤107,pricei 都相等。
另有 15% 的数据,ti≤109,pricei 都相等。
对于 100% 的数据,n≤105,ti≤109,1≤pricei≤1000。
2.1.2 分析
这道题目很长,输入输出也很复杂,这是模拟题的一大特点。
我们在判断乘坐某次公交车的钱可不可以用地铁票兑换的时候,要考虑一下几点:
1.坐公交与坐地铁的时间只差是不是≤45
2.地铁的票价是否<公交的票价
3.是否还有地铁票
如果有很多地铁票堆积,还要考虑用哪张
因为考虑的东西比较多,我们可以定义两个结构体(没学过的不用也行),分别是地铁的和公交的,里面有两个参数,是票价prize和距离上一次乘坐的时间time,经过重重循环和if语句就可以完成了(注意不要漏掉情况哦)
2.1.2 代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int p,t;
}sub[100001],bus[100001];
int n,ans,cnt_sub;
int main(){
scanf("%d",&n);
while(n--){
int op,p,t;
scanf("%d%d%d",&op,&p,&t);
if(op==1){
bool flag=true;
for(int i=max(0,cnt_sub-45);i<cnt_sub;i++){
if(p<=sub[i].p&&t<=sub[i].t){
flag=false;
sub[i].p=0;
sub[i].t=0;
break;
}
}
if(flag){
ans+=p;
}
}else{
sub[cnt_sub].p=p;
sub[cnt_sub].t=t;
sub[cnt_sub].t+=45;
ans+=p;
cnt_sub++;
}
}
printf("%d",ans);
return 0;
}
注:我这里定义了cnt_sub没有定义cnt_bus是因为根本用不到(你试试就知道啦)
因为数据较大,用scanf,printf合适
2.2 坚持不懈的蜗牛(snail)
2.2.1 题目
问题描述:
现在有一只蜗牛,掉入一个6米深的井底,它想爬到井口上面去。蜗牛在第一天的白天能爬3米,但在每天夜晚由于睡觉,它会滑落1米。又由于疲劳因素,以后每个白天它所能爬的高度以第一天爬的高度10%递减,也就是说,下一天比前一天要少爬0.3米。那么蜗牛哪一天才能爬到井口上去呢?在下表中你会看到,蜗牛在第三天爬到井口。
天数 每天初始高度 每天所爬高度 白天到达高度 夜间滑落后高度
1 0 3 3 2
2 2 2.7 4.7 3.7
3 3.7 2.4 6.1 –
问题求解:
你现在要将这个问题一般化。给定不同的参数,最后的结果可能有两种:爬到井口或跌落到井底(注意爬到井口是指青蛙爬的高度大于井口高度,跌倒井底是指青蛙滑落至高度小于0)。你需要计算的是,最终结果如何,以及这个结果发生在哪一天。
输入格式:
输入文件中可包含多个事件,每一行中输入一次事件的4个参数。这四个数分别是:H、U、D、F,参数之间用空格隔开。其中H为井的深度,U是蜗牛在第一天的白天能爬的高度,D是蜗牛每天晚上要滑落的高度,F是疲劳因子(用百分数的形式表示,如30表示为30%)。蜗牛所爬的高度不能为负数,假若由于疲劳因素,我们算出蜗牛该天到达的高度为负,那么认为蜗牛当天根本没有爬。不管蜗牛白天爬多高,它每天晚上都会滑落D米。如果一行四个数都为0,则表示结束。
输出格式:
对于输入中的每个事件(每一行),程序输出一行与之对应。输出结果包括蜗牛是否成功到达要求高度,以及到达该高度的天数。
样例输入:
6 3 1 10
10 2 1 50
50 5 3 14
50 6 4 1
50 6 3 1
0 0 0 0
样例输出:
SUCCESS ON DAY 3
FAILURE ON DAY 4
FAILURE ON DAY 7
FAILURE ON DAY 68
SUCCESS ON DAY 20
时间限制:
1000
空间限制:
65536
2.2.2 分析
又是一道很长的题目,本质上就是简单的蜗牛爬井,唯一的区别就是每个白天速度会减少。我们每个循环先减少速度,然后判断是否爬出井口,或者跌落井底,如果是就输出success第几天或者failure第几天(注意要大写!),如果不是就减掉晚上会滑落的米数(因为如果已经爬出去了或者掉下去了就不用再减了)
2.2.3 代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int h,d;
double sum=0;
double f,u;
while(cin>>h>>u>>d>>f&&(h!=0||u!=0||d!=0||f!=0)){
double num=u;
sum=0.0;
for(int i=1;i<=INT_MAX;i++){
if(u>=0){
sum+=u;
u-=num*f/100;
}
if(sum>h){
cout<<"SUCCESS ON DAY "<<i<<endl;
break;
}else{
sum-=d;
}
if(sum<0){
cout<<"FAILURE ON DAY "<<i<<endl;
break;
}
}
}
return 0;
}
注:while里面的for循环虽然终止条件很大,但是中间会快就会跳出来,所以不用担心
记得用while循环输入输出哦~~
2.3 noip2004普及组 2.花生采摘
2.3.1 题目
鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图1)。有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”
我们假定多多在每个单位时间内,可以做下列四件事情中的一件:
- 从路边跳到最靠近路边(即第一行)的某棵花生植株;
- 从一棵植株跳到前后左右与之相邻的另一棵植株;
- 采摘一棵植株下的花生;
- 从最靠近路边(即第一行)的某棵花生植株跳回路边。
现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。
例如在图2所示的花生田里,只有位于(2, 5), (3, 7), (4, 2), (5, 4)的植株下长有花生,个数分别为13, 7, 15, 9。沿着图示的路线,多多在21个单位时间内,最多可以采到37个花生。
输入格式:
第一行包括三个整数,M, N和K,用空格隔开;表示花生田的大小为M * N(1 <= M, N <= 20),多多采花生的限定时间为K(0 <= K <= 1000)个单位时间。接下来的M行,每行包括N个非负整数,也用空格隔开;第i + 1行的第j个整数Pij(0 <= Pij <= 500)表示花生田里植株(i, j)下花生的数目,0表示该植株下没有花生。
输出格式:
包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。
样例输入:
样例1
6 7 21
0 0 0 0 0 0 0
0 0 0 0 13 0 0
0 0 0 0 0 0 7
0 15 0 0 0 0 0
0 0 0 9 0 0 0
0 0 0 0 0 0 0
样例2
6 7 20
0 0 0 0 0 0 0
0 0 0 0 13 0 0
0 0 0 0 0 0 7
0 15 0 0 0 0 0
0 0 0 9 0 0 0
0 0 0 0 0 0 0
样例输出:
样例1
37
样例2
28
2.3.2 分析
这是一道noip的真题,即使这次例题有点多小编也放上来了😇
还是一个结构体(不会就二维数组吧,不过会有点麻烦哦),这里还需要用到结构体排序这个知识点哦,用sort和一个bool函数就可以完成
结构体里的参数分别是输入进来的cnt,所在的行x,列y
还需要定义一个同样的结构体,表示多多摘完的位置
每次多多都要先判断去哪一株花生摘(也就是花生最多的),然后要判断是否能在鲁滨逊规定的时间内回到路边,如果可以就摘起来,并继续走;如果不行就回到路边输出吧~
2.3.3 代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y,cnt;
}mp[405],dd;
int n,m,k,t=0;
bool cmp(struct node node1,struct node node2){
return node1.cnt>node2.cnt;
}
int main(){
dd.x=0,dd.y=0,dd.cnt=0;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x;
cin>>x;
if(x!=0){
mp[t].cnt=x;
mp[t].x=i;
mp[t].y=j;
t++;
}
}
}
sort(mp,mp+t,cmp);
//k-=1;
bool is_first=true;
for(int i=0;i<t;i++){
if(is_first){
if(k>=mp[i].x*2+1){
is_first=0;
k=k-mp[i].x-1;
dd.x=mp[i].x;
dd.y=mp[i].y;
dd.cnt=mp[i].cnt;
}else{
break;
}
}else{
if(k-abs(dd.x-mp[i].x)-abs(dd.y-mp[i].y)>mp[i].x+1){
k=k-abs(dd.x-mp[i].x)-abs(dd.y-mp[i].y)-1;
dd.x=mp[i].x;
dd.y=mp[i].y;
dd.cnt+=mp[i].cnt;
}else{
break;
}
}
}
cout<<dd.cnt;
return 0;
}
注:代码有点复杂哦,仔细读读,理解一下~~
2.4 水下探测器
2.4.1 题目
题目描述:
水下探测器可以潜入湖中在任意水深进行科学探索。湖水的最大深度为h米,即它在湖底时到水面的距离,0<=h<=100;
探测器最初的水下深度为s米,0<=s<=100;
当探测器不在水面(当前深度大于0)时,每个u指令可使它上浮1米,而当探测器在水面时,u指令是无效的;
当探测器不在湖底(当前深度小于h)时,每个d指令可使它下沉1米,而当探测器在湖底时,d指令是无效的;
在执行到无效指令时,探测器不做任何操作而继续执行下一指令。
编程实现:
根据给定的h、s和一个指令序列(由字符u、d组成的字符串,长度不超过100),求出执行完整的指令序列后,探测器的水下深度。
输入格式:
第一行:h和s,以空格分开。0<=s<=h<=100。
第二行:长度不超过100的指令字符串,串中仅包含字母u或d。
输出格式:
代表探测器在执行指令后的水下深度的数字。
样例输入:
9 1
uduudd
样例输出:
2
2.4.2 分析
好啦好啦,最后一道题~
这道题就比前面三道简单多了,只要每次都用if语句来判断就可以了
要注意的是上浮深度是减少的,下沉深度是增加的
2.4.3 代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int h,s;
string s1;
cin>>h>>s>>s1;
for(int i=0;i<s1.size();i++){
if(s1[i]=='u'&&s!=0){
s--;
}else if(s1[i]=='d'&&s!=h){
s++;
}
}
cout<<s;
return 0;
}
非常非常简单哦
制作不易,点个赞吧😘