王道机试 第二章 暴力求解 2.2 模拟

王道机试 第二章 暴力求解

2.2 模拟

1、图形排版
例2.4 输出梯形(清华大学复试上机题)
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int h;
	while (cin >> h){
		for (int i = h - 1; i >= 0; i--){
			for (int j = 0; j < 2 * h; j++){
				if (i < h && i > j) cout << " ";
				else cout << "*";
			}
			cout << endl;
		}
	}
	return 0;
}
例2.5 Hello World for U
  • 题目解读
    解题的关键是,U型字符的含义,左边和右边垂直部分加底部部分重合了两个字符,最后加起来在原字符串的基础上增加了两个。利用暴力枚举法,根据题目的公式要求计算n1、n2、n3,在输出时需要按行输出。
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;

int main()
{
	string s;
	while (cin >> s)
	{
		int n = s.size();
		int vertical; // 垂直个数
		int space; // U型字符每行空格个数
		for (int n1 = n; n1 >= 1; n1--){ // 全部枚举,取最大的(从大到小尝试,一满足就break)
			int n2 = n1;
			int n3 = n + 2 - n1 - n2;
			if (n3 >= 3 && n3 >= n1){
				vertical = n1;
				space = n3 - 2;
				break;
			}
		}
		for (int i = 0; i < vertical - 1; i++){ // 输出U型两侧(除最底部的那行外)
			cout << s[i];
			for (int j = 0; j < space; j++) cout << " ";
			cout << s[n - 1 - i] << endl;
		}
		for (int i = vertical - 1; i < vertical - 1 + space + 2; i++) // 输出U型最底部
		{
			cout << s[i];
		}
		cout << endl;
	}
	return 0;
}
2、日期问题
例2.6 今年的第几天?(清华大学上机复试题)
  • 闰年判断
    这里需要注意的是,闰年的定义是:能被4整除且不能被100整除,或者能被400整除的年份。
#include <iostream>
#include <cstdio>
using namespace std;

int a[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int b[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int f(int y, int m, int d)
{
	int sum;
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){ // 判断闰年
		sum = 0;
		for (int i = 0; i < m - 1; i++){
			sum += b[i];
		}
		sum += d;
	}
	else{
		sum = 0;
		for (int i = 0; i < m - 1; i++){
			sum += a[i];
		}
		sum += d;
	}
	return sum;
}

int main()
{
	int y, m, d;
	while (cin >> y >> m >> d){
		cout << f(y, m, d) << endl;
	}
	return 0;
}
例2.7 打印日期(华中科技大学复试上机题)
  • 前导零的输出——printf方法
    C语言可以使用printf的%0md格式在原来数字的基础上填充前导零,使得其总位数为m位。
  • 其中,m代表输出的总位数。
  • 例如,m=3时,若原来输出x=22,则使用printf("%03d", x);输出022

输出前导0的C代码如下:

printf("%03d", number); // 输出number,若number不足3位,则将其高位全部填充为0.

本题的C++代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int a[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int b[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int maxn = 15;
int sa[maxn]; // 前缀和,记录闰年前k天的总天数
int sb[maxn]; // 前缀和,记录非闰年前k天的总天数

void solve(int m, int n)
{
	if (n <= 31){
		printf("%04d-%02d-%02d\n", m, 1, n); return;
	}

	if ((m % 4 == 0 && m % 100 != 0) || (m % 400 == 0)){ // 判断闰年
		for (int i = 12; i >= 1; i--){
			if (n >= sa[i]){
				if (n == sa[i]) {printf("%04d-%02d-%02d\n", m, i, a[i - 1]); return;}
				else {printf("%04d-%02d-%02d\n", m, i + 1, n - sa[i]); return;}
			}
		}
	}

	else{
		for (int i = 12; i >= 1; i--){
			if (n >= sb[i]){
				if (n == sb[i]) {printf("%04d-%02d-%02d\n", m, i, b[i - 1]); return;}
				else {printf("%04d-%02d-%02d\n", m, i + 1, n - sb[i]); return;}
			}
		}
	}
}

int main()
{
	int m, n;
	memset(sa, 0, sizeof(sa));
	memset(sb, 0, sizeof(sb));
	sa[1] = a[0]; sb[1] = b[0];
	for (int i = 2; i <= 12; i++){ // 前缀和,记录前k个月的总天数
		sa[i] = sa[i - 1] + a[i - 1]; 
		sb[i] = sb[i - 1] + b[i - 1];
		// cout << sa[i] << " " << sb[i] << endl;
	}
	while (cin >> m >> n)
	{
		solve(m, n);
	}
	return 0;
}
例题2.8 日期累加(北京理工大学复试上机题)

  • 日期累加后,年份可能改变!!!
  • 思路
    1、计算总天数 n n n
    2、判断总天数 n n n是否超出当前年份的天数number_of_year(n)(闰年为366,非闰年为365),若超出则减去当前年份的天数,当前年份++,重复步骤2。否则,根据当前的年份,计算该年份中第n天是几月几日,并输出年月日,注意利用printf填充前导零。
  • 注意
    月份对应天数的数组daytab的每行首个元素均为0。

C++代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

// 坑:日期累加后,年份可能改变!!!

int daytab[][13] = {
	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 0
	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // 1
};

bool is_leap_year(int y){ // 是否为闰年
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
	return false;
}

int number_of_year(int y){ // 每个年份的对应天数
	if (is_leap_year(y)) return 366;
	else return 365;
}

void solve(int y, int m, int d, int add)
{
	int row = is_leap_year(y);
	int n = d; // 总天数
	for (int j = 1; j <= m - 1; j++){ // 计算当前月份之前的那些月份贡献的总天数
		n += daytab[row][j];
	}
	n += add; // 计算增加若干天的总天数
	while (n > number_of_year(y)){ // 重新计算增加天数后的年份
		n -= number_of_year(y);
		y++;
	}
	row = is_leap_year(y); // 判断更新后的年份是否为闰年
	int month = 1;
	while (n > daytab[row][month]){ // 直到小于第month个月份的天数
		n -= daytab[row][month]; 
		month++; // 月份+1
	}
	printf("%04d-%02d-%02d\n", y, month, n);
}

int main()
{
	int y, m, d, add;
	int t; cin >> t;
	while (t--){
		cin >> y >> m >> d >> add;
		solve(y, m, d, add);
	}
	return 0;
}
习题2.6 日期差值(上海交通大学复试上机题)
  • 说明
    本题仍为日期计算,需要将题目的输入转换为年月日,再进行计算。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

int daytab[][13] = {
	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

bool is_leap_year(int y){
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
	return false;
}

int number_of_year(int y){
	if (is_leap_year(y)) return 366;
	return 365;
}

void convert(int n, int &y, int &m, int &d){ // 将输入转换为年月日
	vector<int> a; a.clear();
	int x = n;
	while (x){
		a.push_back(x % 10);
		x /= 10;
	}
	y = ((a[7]*10 + a[6])*10 + a[5])*10 + a[4];
	m = a[3] * 10 + a[2];
	d = a[1] * 10 + a[0];
	// cout << y << " " << m << " " << d << endl;
}

int days(int y0, int y, int m, int d){ // 以y0年为基准的天数
	int row = is_leap_year(y);
	while (y > y0){ // 年
		d += number_of_year(y - 1); // 年份之间的天数,从y0到y-1
		y--;
	}
	for (int i = 1; i <= m - 1; i++){ // 月
		d += daytab[row][i];
	}
	return d;
}

int main()
{
	int a, b;
	int y1, m1, d1;
	int y2, m2, d2;
	int ans = 1;
	while (cin >> a >> b){
		if (a < b) swap(a, b); // 默认前者比后者时间长
		convert(a, y1, m1, d1);
		convert(b, y2, m2, d2);
		// cout << y1 << " " << m1 << " " << d1 << endl;
		// cout << y2 << " " << m2 << " " << d2 << endl;
		int ans1 = days(y2, y1, m1, d1);
		int ans2 = days(y2, y2, m2, d2);
		// cout << ans1 << " " << ans2 << endl;
		ans = ans + ans1 - ans2;
		cout << ans << endl; // output
	}
	return 0;
}
习题2.7 Day of Week
  • 思路
    1、计算基准年月日1000-01-01是星期几(利用题目给出的9 October 2001 是星期二对以7位周期倒退)。
    2、再计算输入年月日与其的天数差days,若等于7则星期一致,否则将天数差days对7取模即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <string>
using namespace std;

int daytab[][13] = {
	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

map <string, int> month_to_number = {
{"January", 1}, {"February", 2}, {"March", 3}, {"April", 4}, {"May", 5}, {"June", 6},
{"July", 7}, {"August", 8}, {"September", 9}, {"October", 10}, {"November", 11}, {"December", 12}};

map <int, string> number_to_month = {
{1, "Monday"}, {2, "Tuesday"}, {3, "Wednesday"}, {4, "Thursday"}, 
{5, "Friday"}, {6, "Saturday"}, {7, "Sunday"}};

bool is_leap_year(int y){
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
	return false;
}

int number_of_year(int y){
	if (is_leap_year(y)) return 366;
	else return 365;
}

int solve(int y, int m, int d){
	int row = is_leap_year(y);
	while (y > 1000){
		y--;
		d = d + number_of_year(y);
	}
	for (int i = 1; i <= m - 1; i++){
		d += daytab[row][i];
	}
	return d - 1;
}

int main()
{
	int d, y, m;
	string s;
	while (cin >> d >> s >> y){
		m = month_to_number[s];
		int days0 = solve(2001, 10, 9);
		int sum = 2; // 从星期二倒退(9 October 2001 是星期二)
		while (sum < days0){
			sum = sum + 7;
		}
		sum = sum - days0; // 1000年1月1日的星期

		int day = solve(y, m, d);
		day = day + 7 - 4;
		if (day == 0) cout << number_to_month[sum] << endl;  //返回1000年1月1日是星期几
		else if (day % 7 == 0) cout << "Sunday\n";
		else cout << number_to_month[(day % 7)] << endl;
	}
	return 0;
}
习题2.8 日期类(北京理工大学复试上机题)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

// 坑:日期累加后,年份可能改变!!!

int daytab[][13] = {
	{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // 0
	{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // 1
};

bool is_leap_year(int y){ // 是否为闰年
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) return true;
	return false;
}

int number_of_year(int y){ // 每个年份的对应天数
	if (is_leap_year(y)) return 366;
	else return 365;
}

void solve(int y, int m, int d, int add)
{
	int row = is_leap_year(y);
	int n = d; // 总天数
	for (int j = 1; j <= m - 1; j++){ // 计算当前月份之前的那些月份贡献的总天数
		n += daytab[row][j];
	}
	n += add; // 计算增加若干天的总天数
	while (n > number_of_year(y)){ // 重新计算增加天数后的年份
		n -= number_of_year(y);
		y++;
	}
	row = is_leap_year(y); // 判断更新后的年份是否为闰年
	int month = 1;
	while (n > daytab[row][month]){ // 直到小于第month个月份的天数
		n -= daytab[row][month]; 
		month++; // 月份+1
	}
	printf("%04d-%02d-%02d\n", y, month, n);
}

int main()
{
	int y, m, d, add;
	int t; cin >> t;
	while (t--){
		cin >> y >> m >> d;
		int add = 1;
		solve(y, m, d, add);
	}
	return 0;
}
3、其他模拟
例题2.9 剩下的树(清华大学复试上机题)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 10005;
bool tree[maxn];

int main()
{
	int L, m, a, b;
	cin >> L >> m;
	fill(tree, tree + maxn, 1);
	while (m--){
		cin >> a >> b;
		for (int i = a; i <= b; i++){
			tree[i] = false;
		}
	}
	int cnt = 0;
	for (int i = 0; i <= L; i++){
		if (tree[i]) cnt++;
	}
	cout << cnt << endl;
	return 0;
}
例题2.10 手机键盘
  • 解题关键
    1、要知道九宫格输入法的键盘布局
    2、判断两个字母是否在同一个按键上的方法:若两个字母的位置之差等于时间之差,则它们在同一个按键上。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int times[] = {
	1, 2, 3, // abc
	1, 2, 3, // def
	1, 2, 3, // ghi
	1, 2, 3,  // jkl
	1, 2, 3, // mno
	1, 2, 3, 4, // pqrs
	1, 2, 3, // tuv
	1, 2, 3, 4 // wxyz
};

int main()
{
	string s;
	while (cin >> s){
		int ans = 0;
		for (int i = 0; i < s.size(); i++){
			ans += times[s[i] - 'a'];
			if (i != 0 && s[i] - s[i - 1] == times[s[i] - 'a'] - times[s[i - 1] - 'a']){
				ans += 2;
			}
		}
		cout << ans << endl;
	}
	return 0;
}
例题2.11 XXX定律(浙江大学复试上机题)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

// 对于一个数n,如果是偶数,就把n砍掉一半;如果是奇数,把n变成 3*n+ 1后砍掉一半,直到该数变为1为止。     
// 请计算需要经过几步才能将n变到1,具体可见样例。

int main()
{
	int n;
	while (cin >> n && n){
		int cnt = 0;
		while (n != 1){
			if (n % 2 == 0) {n /= 2; cnt++;}
			else{n = 3 * n + 1; n /= 2; cnt++;}
		}
		cout << cnt << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值