模拟算法依据题目规则逐步实现解决问题,常见于编程竞赛。文章阐述其特点与技巧,强调模块化设计与清晰思路。通过单身贵族游戏、缩位求和、长草、拉马车等多个经典例题案例,展示基础模拟、日期处理及复杂状态模拟的实现方法。提供 Java 与 C++ 双语言代码参考,解析输入输出逻辑与边界处理,辅助提升算法实战能力。
#include<iostream>#include<vector>usingnamespace std;
intmain(){
vector<vector<int>> vec(7, vector<int>(7, 0));
for (int i = 0; i < 7; ++i) {
string str;
cin >> str;
if (str.size() == 3) {
for (int j = 0; j < 3; ++j) {
vec[i][j + 2] = str[j] - '0';
}
} else {
for (int j = 0; j < 7; ++j) {
vec[i][j] = str[j] - '0';
}
}
}
bool flag = true;
for (int i = 1; i < 6; ++i) {
for (int j = 1; j < 6; ++j) {
if (vec[i][j] == 1) {
if (vec[i][j - 1] == 1 || vec[i][j + 1] == 1 || vec[i - 1][j] == 1 || vec[i + 1][j] == 1) {
flag = false;
}
}
}
}
if (flag) cout << "yes" << endl;
else cout << "no" << endl;
return0;
}
2. 简简单单的暴力题
问题描述
有一个长为 n 的序列 a1,a2.....an 与一个特殊的数 k,ai 小于 k。
当一个序列(元素个数 size≥2)中有一个数 x 会等于其他数的总和 sum % k,即 sum % k == x,则说明此序列为好序列。
求在长度为 n 的序列中有多少连续的子序列为好序列。
输入格式
第一行包含两个数 n,k,表示序列长和特殊的数。
第二行包含 n 个小于 k 的非负整数。
输出格式
输出一个数 sum 为好序列个数。
import java.util.Scanner;
publicclassMain {
publicstaticvoidmain(String[] args) {
Scannerscanner=newScanner(System.in);
intn= scanner.nextInt();
intk= scanner.nextInt();
int[] vec = newint[n];
for (inti=0; i < n; i++) {
vec[i] = scanner.nextInt();
}
intnum=0;
for (inti=0; i < n; i++) {
for (intj= i + 1; j < n; j++) {
intsum=0;
for (intz= i; z <= j; z++) {
sum += vec[z];
}
for (intz= i; z <= j; z++) {
sum -= vec[z];
if (sum % k == vec[z]) {
num++;
break;
}
sum += vec[z];
}
}
}
System.out.println(num);
scanner.close();
}
}
#include<iostream>#include<vector>usingnamespace std;
intmain(){
int n, k;
cin >> n >> k;
vector<int> vec(n, 0);
for (int i = 0; i < n; ++i) cin >> vec[i];
int num = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
int sum = 0;
for (int z = i; z <= j; ++z) sum += vec[z];
for (int z = i; z <= j; ++z) {
sum -= vec[z];
if (sum % k == vec[z]) {
num++;
break;
}
sum += vec[z];
}
}
}
cout << num << endl;
return0;
}
3. 小浩的国际象棋
问题描述
小浩有一个大小为 N×N 的国际象棋棋盘。
有 N 个主教以之字形的形式放置在棋盘的矩阵上,坐标分别为 (1,1),(2,2),(1,3),(2,4),(1,5),…。
输入的第一行包含两个整数 n,m。
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。其中,2≤n,m≤1000,1≤k≤1000。
输出描述
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
import java.util.Scanner;
publicclassGrassGrowthSimulation {
staticint[][] a = newint[1005][1005];
staticint[][] b = newint[1005][1005];
publicstaticvoidmain(String[] args) {
Scannerscanner=newScanner(System.in);
intn= scanner.nextInt();
intm= scanner.nextInt();
scanner.nextLine();
for (inti=0; i < n; i++) {
Stringstr= scanner.nextLine();
for (intj=0; j < m; j++) {
if (str.charAt(j) == '.') a[i][j] = 0;
else a[i][j] = 1;
}
}
intk= scanner.nextInt();
scanner.close();
while (k-- > 0) {
dfs(n, m);
}
for (inti=0; i < n; i++) {
for (intj=0; j < m; j++) {
if (a[i][j] == 0) System.out.print(".");
else System.out.print("g");
}
System.out.println();
}
}
publicstaticvoiddfs(int n, int m) {
for (inti=0; i < n; i++) {
for (intj=0; j < m; j++) {
b[i][j] = a[i][j];
}
}
for (inti=0; i < n; i++) {
for (intj=0; j < m; j++) {
if (b[i][j] == 1) {
if (i >= 1) a[i - 1][j] = 1;
if (i < n - 1) a[i + 1][j] = 1;
if (j >= 1) a[i][j - 1] = 1;
if (j < m - 1) a[i][j + 1] = 1;
}
}
}
}
}
#include<iostream>usingnamespace std;
int a[1005][1005], b[1005][1005];
voiddfs(int n, int m){
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
b[i][j] = a[i][j];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (b[i][j] == 1) {
if (i >= 1) a[i - 1][j] = 1;
if (i < n - 1) a[i + 1][j] = 1;
if (j >= 1) a[i][j - 1] = 1;
if (j < m - 1) a[i][j + 1] = 1;
}
}
}
}
intmain(){
int n, m, k;
cin >> n >> m;
string str;
for (int i = 0; i < n; ++i) {
cin >> str;
for (int j = 0; j < m; ++j) {
if (str[j] == '.') a[i][j] = 0;
else a[i][j] = 1;
}
}
cin >> k;
while (k--) {
dfs(n, m);
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (a[i][j] == 0) cout << ".";
else cout << "g";
}
cout << endl;
}
return0;
}
#include<bits/stdc++.h>usingnamespace std;
vector<int> generateNum(string str, int range){
vector<int> res;
int cur = 0;
int lis = -1;
for (char c : str) {
if (c == ',') {
res.push_back(cur);
cur = 0;
} elseif (c == '-') {
lis = cur;
cur = 0;
} elseif (c == '*') {
for (int i = 0; i < range; i++) res.push_back(i + 1);
return res;
} else {
cur = cur * 10 + c - '0';
}
}
if (lis != -1) {
for (int i = lis; i <= min(range, cur); ++i) res.push_back(i);
} else {
res.push_back(cur);
}
return res;
}
intmain(){
int monthDay[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
string S, M, H, D, MON;
cin >> S >> M >> H >> D >> MON;
int num1 = generateNum(S, 60).size() * generateNum(M, 60).size() * generateNum(H, 24).size();
int num2 = 0;
for (int i : generateNum(MON, 12)) {
num2 += generateNum(D, monthDay[i - 1]).size() * num1;
}
cout << num2 << endl;
return0;
}
进阶
12. 赢球票
题目描述
某机构举办球票大奖赛。获奖选手有机会赢得若干张球票。
主持人拿出 N 张卡片(上面写着 1⋯N 的数字),打乱顺序,排成一个圆圈。
你可以从任意一张卡片开始顺时针数数:1,2,3 ⋯⋯
如果数到的数字刚好和卡片上的数字相同,则把该卡片收入囊中,从下一个卡片重新数数。
直到再无法收获任何卡片,游戏结束。囊中卡片数字的和就是赢得球票的张数。
本题的目标:已知顺时针卡片序列,随便你从哪里开始数,求最多能赢多少张球票。
输入描述
第一行一个整数 N (N≤100),表示卡片数目。
第二行 N 个整数,表示顺时针排列的卡片。
输出描述
输出一行,一个整数,表示最好情况下能赢得多少张球票。
import java.util.Scanner;
import java.util.Arrays;
publicclassCardGame {
publicstaticvoidmain(String[] args) {
Scannerscanner=newScanner(System.in);
intn= scanner.nextInt();
int[] vec = newint[n];
for (inti=0; i < n; i++) {
vec[i] = scanner.nextInt();
}
intflag=0;
for (inti=0; i < n; i++) {
boolean[] used = newboolean[n];
intcur=0;
intindex= i;
intcount=1;
intnum=0;
while (true) {
if (!used[index]) {
if (vec[index] == count) {
cur++;
num += count;
used[index] = true;
count = 1;
} else {
count++;
}
}
index = (index + 1) % n;
if (count > n || cur == n) break;
}
flag = Math.max(num, flag);
}
System.out.println(flag);
scanner.close();
}
}
#include<iostream>#include<vector>usingnamespace std;
intmain(){
int n;
cin >> n;
vector<int> vec(n, 0);
for (int i = 0; i < n; ++i) cin >> vec[i];
int flag = 0;
for (int i = 0; i < n; ++i) {
vector<bool> used(n, false);
int cur = 0;
int index = i;
int count = 1;
int num = 0;
while (1) {
if (!used[index]) {
if (vec[index] == count) {
cur++;
num += count;
used[index] = true;
count = 1;
} else {
count++;
}
}
index = (index + 1) % n;
if (count > n || cur == n) break;
}
flag = max(num, flag);
}
cout << flag << endl;
return0;
}
13. 神奇闹钟
问题描述
小蓝发现了一个神奇的闹钟,从纪元时间(1970 年 1 月 1 日 00:00:00)开始,每经过 x 分钟,这个闹钟便会触发一次闹铃。