数组模拟操作
什么是模拟
模拟顾名思义,就是按照题目的要求,一步步写出代码。
题目要求怎么做就怎么做,用代码的形式描述出来。
模拟的过程
(1)读题。读懂题目的意思。
(2)建模。将问题抽象成模型,选择合理的算法和数据结构(比如定义数组来记录一组事物的状态)。
(3)代码实现。
矩阵的折叠
引言
一张纸我们可以从中间把它对折。
想象一下,如果给你若干个数组成的数组,我们可以把它对折起来吗?
问题
有这样一个数组int a[6]={3,5,2,6,9,1};
现在要求你,将这个数组的右半边折向左半边,重叠的数字加起来,这个数组会变成什么样子?
应该会变成4,14,8(数组的长度减半,对应元素相加)。
思考
1)如果是n个元素组成的数组,折叠后数组的长度是?
不能直接写n/2,如果n是奇数,比如5个数,折叠后应该剩3个。
折叠后数组的长度是 (n+1)/2。
2)折叠时第i个元素和第几个元素叠加?
第1个元素和第n个元素叠加,第2个元素和第n-1个元素叠加,…… ,第i个元素和第n+1-i个元素叠加
竞赛模拟真题
引言
模拟在编程比赛中出现的概率是非常高的,而且模拟题不像其他类型的题用固定的解法来做,模拟题需要根据不同的题建立不同的模型,思考出合适的解法。
想要训练解模拟题,最好的方法就是多看多做,见得多了,自己也能总结出一套合适自己的方法。这节课我们就来看几道编程比赛中的模拟真题。
龙虎斗
题目描述轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n个兵营(自左至右编号1~n),相邻编号的兵营之间相隔 1厘米,即棋盘为长度为 n-1厘米的线段。i号兵营里有 ci位工兵。
轩轩在左侧,代表“龙”;凯凯在右侧,代表“虎”。 他们以 m号兵营作为分界, 靠左的工兵属于龙势力,靠右的工兵属于虎势力,而第 m 号兵营中的工兵很纠结,他们不属于任何一方。
一个兵营的气势为:该兵营中的工兵数× 该兵营到 m 号兵营的距离;参与游戏一方的势力定义为:属于这一方所有兵营的气势之和。
游戏过程中,某一刻天降神兵,共有 s1位工兵突然出现在了 p1号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p2,并将你手里的 s2 位工兵全部派往 兵营 p2,使得双方气势差距尽可能小。
注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在 m号兵营,则不属于任何势力)。
分析: 本题题目描述很复杂,不过读懂题目之后解题思路应该能比较清楚。
分别算出龙、虎阵营的势力(加上天降神兵的势力),如果算出来龙方势力较弱,就往龙方的兵营(或者也可能是往中立兵营)加人;如果算出来虎方势力较弱,就往虎方的兵营(或者也可能是往中立兵营)加人,要使得势力差尽量小。
#include<iostream>
#include<cmath>
using namespace std;
long long n,m,p1,p2,s1,s2,x,y,diff,c[100005];
int main()
{
cin>>n;
for(int i=1;i<=n;i++){ //每个兵营的人数
cin>>c[i];
}
cin>>m>>p1>>s1>>s2;
for(int i=1;i<m;i++){ //龙方气势
x+=(m-i)*c[i];
}
for(int i=m+1;i<=n;i++){ //虎方气势
y+=(i-m)*c[i];
}
if(p1<m) x+=(m-p1)*s1; //天降神兵加入龙方
if(p1>m) y+=(p1-m)*s1; //天降神兵加入虎方
diff=abs(x-y); //两方势力差
p2=m;
if(x<y){ //如果龙方弱
for(int i=1;i<m;i++){ //寻找龙方兵营(或中立兵营)加入,使得势力差尽量小
if(abs(x+(m-i)*s2-y)<diff){
diff=abs(x+(m-i)*s2-y);
p2=i;
}
}
}
else if(x>y){ //寻找虎方兵营(或中立兵营)加入,使得势力差尽量小
for(int i=m+1;i<=n;i++){
if(abs(y+(i-m)*s2-x)<diff){
diff=abs(y+(i-m)*s2-x);
p2=i;
}
}
}
cout<<p2;
return 0;
}
简单模型+复杂模拟
报数游戏1
题目描述:有n个人围成一圈,按顺序从1到n编号。从第一个人开始报数,报数4的人退出圈子,下一个人从1开始重新报数,报数4的人退出圈子… …如此循环,直到留下最后一个人。问最后留下来的人的编号。
分析: 首先选择合适的数据类型(数组),可以利用数组来标记n个人的状态(是否离开圈子)。
一开始,n个人都在圈里,可以给数组元素全赋值为1表示在圈子里。
后面模拟报数的过程,我们一遍一遍地遍历数组,每次计数4个人在圈子里(找到了4个值为1的数组元素),则第4个人出圈(对应元素值置为0),同时要定义一个计数器记录圈子中剩的人数,当圈子里只剩1人时即停止。
#include<iostream>
using namespace std;
int a[55],n; //定义a数组标记每个人的状态
int main(){
cin>>n;
for(int i=1;i<=n;i++){ //数组元素初值全赋为1,表示都在
a[i]=1;
}
int s=n,sum=0; //s记录圈子里的人数
while(s>1){
for(int i=1;i<=n;i++){
sum+=a[i]; //在圈子里的人(a[i]值为1)报数
if(sum==4){
a[i]=0; //标记离开
sum=0;
s--;
}
}
}
for(int i=1;i<=n;i++){ //找留下的人
if(a[i]){
cout<<i;
break;
}
}
return 0;
}