暴力求解——习题
学习完第一章–暴力求解之后,当然要做相应地练习啦~
https://blog.csdn.net/Window_mouse/article/details/128632426
注:上述习题都可以在牛客进行测试。
例如,第9题链接:xxx定律_牛客题霸_牛客网 (nowcoder.com),其他题目在“题目列表”中基本都可以找到。
另外,此文章仅仅是提供解题思路,并非最优解。
1 与7无关的数–北京大学
描述:
一个正整数,如果它能被7整除,或者它的十进制表示法中某个位数上的数字为7, 则称其为与7相关的数.现求所有小于等于n(n<100)的与7无关的正整数的平方和。
输入描述:
案例可能有多组。对于每个测试案例输入为一行,正整数n,(n<100)
输出描述:
对于每个测试案例输出一行,输出小于等于n的与7无关的正整数的平方和。
示例1
输入:
21
输出:
2336
题解:
与7相关的数,假设为num
num只需满足以下条件之一,即称num为与7相关的数
1.num能被7整除
num % 7 = 0
2.num中某个位的数字为7
依次求每个位上的数,判断是否含有7
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 判断正整数num是否为与7相关的数
* @param num
* @return true, 与7相关的数;false, 与7无关的数
*/
bool isRelevantNum(int num) {
if (num % 7 == 0) {
//num能被7整除
return true;
} else {
//num的某个位数上为7
while (num != 0) {
if (num % 10 == 7) {
return true;
}
num /= 10;
}
}
return false;
}
/**
* 与7无关的数--北京大学
* @return
*/
int main() {
int n;
while (cin >> n) {
int sum = 0;
for (int num = 0; num <= n; ++num) {
if (!isRelevantNum(num)) {
//求和
sum += num * num;
}
}
//输出sum
cout << sum << endl;
}
return 0;
}
2 百鸡问题–哈尔滨工业大学
描述:
用小于等于n元去买100只鸡,大鸡5元/只,小鸡3元/只,还有1/3元每只的一种小鸡,分别记为x只,y只,z只。编程求解x,y,z所有可能解。
输入描述:
测试数据有多组,输入n。
输出描述:
对于每组输入,请输出x,y,z所有可行解,按照x,y,z依次增大的顺序输出。
示例1
输入:
40
输出:
x=0,y=0,z=100
x=0,y=1,z=99
x=0,y=2,z=98
x=1,y=0,z=99
题解:
暴力求解,思路还是很好想的,三层for循环。
for循环中,稍微优化一下,减少循环次数,虽然感觉效果不明显。比如,300<n<500时,x最大为n/5即可;当n<300时,而y最大为n/3即可。
然后,再判断是否满足两个条件:
1. x+y+z=100
2. 5*x+3*y+z/3 <= n,但是有点小问题,z/3是会进行向下取整操作的。此外,除法结果的某些小数计算机是无法正确表示,即会出现精度问题。
所以,我们换个思路,将乘除法换成乘法,问题即可迎刃而解。
5*x+3*y+z/3 <= n 转化成 3*5*x+3*3*y+z = 15*x+9*y+z <= 3*n
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 百鸡问题--哈尔滨工业大学
* @return
*/
int main() {
int n;
while (cin >> n) {
for (int x = 0; x <= 100; ++x) {
for (int y = 0; y <= 100; ++y) {
for (int z = 0; z <= 100; ++z) {
//满足x+y+z=100只
if (x + y + z == 100) {
if (15 * x + 9 * y + z <= 3 * n) {
printf("x=%d,y=%d,z=%d\n", x, y, z);
}
}
}
}
}
}
return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 百鸡问题--哈尔滨工业大学
* @return
*/
int main() {
int n;
int xMax = 100;
int yMax = 100;
if (n <= 5 * 100) {
xMax = n / 5;
} else if (n <= 3 * 100) {
yMax = n / 3;
}
while (cin >> n) {
for (int x = 0; x <= xMax; ++x) {
for (int y = 0; y <= yMax; ++y) {
for (int z = 0; z <= 100; ++z) {
//满足x+y+z=100只
if (x + y + z == 100) {
if (15 * x + 9 * y + z <= 3 * n) {
printf("x=%d,y=%d,z=%d\n", x, y, z);
}
}
}
}
}
}
return 0;
}
3 Old Bill–上海交通大学
描述:
Among grandfather’s papers a bill was found. 72 turkeys $679 The first and the last digits of the number that obviously represented the total price of those turkeys are replaced here by blanks (denoted _), for they are faded and are illegible. What are the two faded digits and what was the price of one turkey? We want to write a program that solves a general version of the above problem. N turkeys $XYZ The total number of turkeys, N, is between 1 and 99, including both. The total price originally consisted of five digits, but we can see only the three digits in the middle. We assume that the first digit is nonzero, that the price of one turkeys is an integer number of dollars, and that all the turkeys cost the same price. Given N, X, Y, and Z, write a program that guesses the two faded digits and the original price. In case that there is more than one candidate for the original price, the output should be the most expensive one. That is, the program is to report the two faded digits and the maximum price per turkey for the turkeys.
输入描述:
The first line of the input file contains an integer N (0<N<100), which represents the number of turkeys. In the following line, there are the three decimal digits X, Y, and Z., separated by a space, of the original price $XYZ.
输出描述:
For each case, output the two faded digits and the maximum price per turkey for the turkeys.
示例1
输入:
72
6 7 9
5
2 3 7
78
0 0 5
输出:
3 2 511
9 5 18475
0
题解:
只要看懂了题目,其实本题还是比较基础的。
分析:
已知条件:
1.火鸡的数量n
2.总价格sumPrice的千、百、十位数,sumPrice = _XYZ_ = aXYZb,其中XYZ已知
求:
火鸡的单价price(有多个则求最大单价maxPrice),总价格的第一位和最后一位,分别设为a、b
注意点:
1.火鸡的单价price为整数,所以满足 sumPrice % n == 0
2.a != 0
#include <iostream>
#include <cstdio>
using namespace std;
/**
* Old Bill--上海交通大学
* @return
*/
int main() {
int n;
int x, y, z;
while (cin >> n >> x >> y >> z) {
int price = 0;
int maxPrice = 0;
int sumPrice = 0;
int a, b;
//第一个数字非0,所以从1开始循环
for (int i = 1; i <= 9; ++i) {
for (int j = 0; j <= 9; ++j) {
//_XYZ_ 总价格
sumPrice = i * 10000 + x * 1000 + y * 100 + z * 10 + j;
/*
* 因为要保证火鸡的单格为整数,而 单价=总价格/数量
* 所以,通过sumPrice%n==0过滤不整除的情况
*/
if (sumPrice % n == 0) {
price = sumPrice / n;
a = i;
b = j;
//多个单价,则求最大单价
if (price > maxPrice) {
maxPrice = price;
}
}
}
}
if (maxPrice != 0) {
printf("%d %d %d\n", a, b, maxPrice);
} else {
//特殊情况 price=0
printf("0\n");
}
}
return 0;
}
4 Hello World for U–浙江大学
描述:
Given any string of N (>=5) characters, you are asked to form the characters into the shape of U. For example, “helloworld” can be printed as: h d e l l r lowo That is, the characters must be printed in the original order, starting top-down from the left vertical line with n1 characters, then left to right along the bottom line with n2 characters, and finally bottom-up along the vertical line with n3 characters. And more, we would like U to be as squared as possible – that is, it must be satisfied that n1 = n3 = max { k| k <= n2 for all 3 <= n2 <= N } with n1 + n2 + n3 - 2 = N.
输入描述:
There are multiple test cases.Each case contains one string with no less than 5 and no more than 80 characters in a line. The string contains no white space.
输出描述:
For each test case, print the input string in the shape of U as specified in the description.
示例1
输入:
helloworld!
www.nowcoder.com
输出:
h !
e d
l l
lowor
w m
w o
w c
. .
n r
owcode
题解:
将长度为len字符串分为3段n1,n2,n3,其中n1和n3长度相同,且n1+n2+n3=len+2。
所以,n1=n2=(len+2)/3,n3=len+2-2*n1。
打印时,逐行打印即可。除去最后一行,其余行先打印1个n1的字符,再打印n2-2个空格,最后打印n3的字符。最后一行打印n2即可。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a605ee54f7714bc7922bb87af8719fae.png#pic_center x=500x700)
#include <iostream>
#include <cstdio>
using namespace std;
/**
* Hello World for U -- 浙江大学
* @return
*/
int main() {
string str;
cin >> str;
int len = str.length();
int n1 = (len + 2) / 3;
int n2 = len + 2 - 2 * n1;
int n3 = n1;
/*
* 打印字符
* 除去最后一行,所以循环n1-1次
*/
for (int i = 0; i < n1 - 1; ++i) {
//打印n1的字符
cout << str[i];
//打印n2-2个空格
for (int j = 0; j < n2 - 2; ++j) {
cout << " ";
}
//打印n3的字符
cout << str[len - i - 1];
//换行
cout << endl;
}
/*
* 打印最后一行
*/
for (int k = 0; k < n2; ++k) {
cout << str[n1 - 1 + k];
}
return 0;
}
5 日期累加–北京理工大学
描述:
设计一个程序能计算一个日期加上若干天后是什么日期。
输入描述:
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。
输出描述:
输出m行,每行按yyyy-mm-dd的个数输出。
示例1
输入:
1
2008 2 3 100
输出:
2008-05-13
题解:
分析:
year.month.day dayNumber
2000-11-11 400
1. 先将"日"置0,2000-11-0 411
2. 判断dayNumber是否大于一个完整月的天数(注意判断闰年和平年)
1. 若大于,则减去相应的天数,同时month++(注意若month为12,则需置0且year++)
2. 若小于等于,则year-month-dayNumber即为最后的日期
3. 循环2
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 空间换时间
* 二维数组保存平年和闰年0~12月份对应的天数
*/
int dayTable[2][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} //闰年
};
/**
* 判断是否为闰年
* 若是闰年,则返回1,对应dayTable[1][];反之,返回0,对应dayTable[0][]
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 日期累加--北京理工大学
* @return
*/
int main() {
//m组样例
int m;
cin >> m;
for (int i = 0; i < m; ++i) {
int year, month, day;
int dayNumber;
//用户输入
cin >> year >> month >> day >> dayNumber;
//判断当前年份是否为闰年
int row = isLeapYear(year);
//先把“天数”单独拿出来,后续只需考虑年份和月份即可
dayNumber += day;
while (dayNumber > dayTable[row][month]) {
//dayNumber减去一个完整月的天数
dayNumber -= dayTable[row][month];
//若月份为12,则年份需要+1,同时月份置为0
if (month == 12) {
month = 0;
year++;
row = isLeapYear(year);
}
month++;
}
//最后剩余不足一个完整月的天数
day = dayNumber;
//按照要求格式输出yyyy-mm-dd
printf("%4d-%02d-%02d\n", year, month, day);
}
return 0;
}
6 日期差值–上海交通大学
描述:
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天
输入描述:
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD
输出描述:
每组数据输出一行,即日期差值
示例1
输入:
20110412
20110422
输出:
11
题解:
假设日期为 year.month.day,我们分别计算两个日期与0001.01.01的差值
最后求两个差值相减去绝对值加1即可。
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 空间换时间
* 二维数组保存平年和闰年0~12月份对应的天数
*/
int dayTable[2][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} //闰年
};
/**
* 判断是否为闰年
* 若是闰年,则返回1,对应dayTable[1][];反之,返回0,对应dayTable[0][]
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 返回一个完整年的天数
* 闰年366天,平年365天
* @param year
* @return
*/
int getDayNumOfYear(int year) {
return isLeapYear(year) ? 366 : 365;
}
/**
* 获取从 0001.01.01 至 year.month.day 之间的天数
* @param year
* @param month
* @param day
* @return
*/
int getSumDayNum(int year, int month, int day) {
int dayNumber = 0;
for (int i = 1; i < year; ++i) {
dayNumber += getDayNumOfYear(i);
}
for (int j = 0; j < month; ++j) {
dayNumber += dayTable[isLeapYear(year)][j];
}
dayNumber += day;
return dayNumber;
}
/**
* 日期差值--上海交通大学
* @return
*/
int main() {
string date01, date02;
while (cin >> date01 >> date02) {
int year01 = 0, month01 = 0, day01 = 0;
int year02 = 0, month02 = 0, day02 = 0;
/*
* 格式化日期,获取年、月、日
*/
for (int i = 0; i < date01.length(); ++i) {
if (i <= 3) {
year01 *= 10;
year01 += date01[i] - '0';
} else if (i > 3 && i <= 5) {
month01 *= 10;
month01 += date01[i] - '0';
} else {
day01 *= 10;
day01 += date01[i] - '0';
}
}
for (int j = 0; j < date02.length(); ++j) {
if (j <= 3) {
year02 *= 10;
year02 += date02[j] - '0';
} else if (j > 3 && j <= 5) {
month02 *= 10;
month02 += date02[j] - '0';
} else {
day02 *= 10;
day02 += date02[j] - '0';
}
}
int sumDay01 = getSumDayNum(year01, month01, day01);
int sumDay02 = getSumDayNum(year02, month02, day02);
int ans = abs(sumDay01 - sumDay02) + 1;
cout << ans << endl;
}
return 0;
}
7 Day of Week–上海交通大学
描述:
We now use the Gregorian style of dating in Russia. The leap years are years with number divisible by 4 but not divisible by 100, or divisible by 400. For example, years 2004, 2180 and 2400 are leap. Years 2005, 2181 and 2300 are not leap. Your task is to write a program which will compute the day of week corresponding to a given date in the nearest past or in the future using today’s agreement about dating.
编写一个程序,计算给定的日期是星期几。
输入描述:
There is one single line contains the day number d, month name M and year number y(1000≤y≤3000). The month name is the corresponding English name starting from the capital letter.
输出描述:
Output a single line with the English name of the day of week corresponding to the date, starting from the capital letter. All other letters must be in lower case. Month and Week name in Input/Output: January, February, March, April, May, June, July, August, September, October, November, December Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
示例1
输入:
9 October 2001
14 October 2001
复制
输出:
Tuesday
Sunday
题解:
隐含0001.01.01是周一,所以我们计算输入的日期与0001.01.01之间的差值天数,然后对7取模,即可知道偏移多少天。
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 二维数组保存平年和闰年0~12月份对应的天数
*/
int dayTable[2][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} //闰年
};
/*
* 星期名称的字符串
*/
char weekDayTable[8][15] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
/*
* 月份名称的字符串
*/
char monthTable[13][15] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September",
"October", "November", "December"};
/**
* 判断是否为闰年
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 返回一个完整年的天数
* 闰年366天,平年365天
* @param year
* @return
*/
int getDayNumOfYear(int year) {
return isLeapYear(year) ? 366 : 365;
}
/**
* Day of Week--上海交通大学
* @return
*/
int main() {
int year;
int month;
string monthStr;
int day;
while (cin >> day >> monthStr >> year) {
//确定月份
for (int i = 0; i <= 12; ++i) {
if (monthStr == monthTable[i]) {
month = i;
break;
}
}
//计算距离0001.01.01的天数,0001.01.01是周一
int dayNumber = 0;
//年份要从0001开始,不可以从0000开始
for (int j = 1; j < year; ++j) {
dayNumber += getDayNumOfYear(j);
}
for (int k = 0; k < month; ++k) {
dayNumber += dayTable[isLeapYear(year)][k];
}
dayNumber += day;
//dayNumber%7即可
cout << weekDayTable[dayNumber % 7] << endl;
}
return 0;
}
8 日期类–北京理工大学
描述:
编写一个日期类,要求按xxxx-xx-xx 的格式输出日期,实现加一天的操作。
输入描述:
输入第一行表示测试用例的个数m,接下来m行每行有3个用空格隔开的整数,分别表示年月日。测试数据不会有闰年。
输出描述:
输出m行。按xxxx-xx-xx的格式输出,表示输入日期的后一天的日期。
示例1
输入:
2
1999 10 20
2001 1 31
输出:
1999-10-21
2001-02-01
备注:
注意个位数日期前面要有0。
题解:
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 二维数组保存平年和闰年0~12月份对应的天数
*/
int dayTable[2][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} //闰年
};
/**
* 判断是否为闰年
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 日期类--北京理工大学
* @return
*/
int main() {
int year, month, day;
int m;
cin >> m;
for (int i = 0; i < m; ++i) {
cin >> year >> month >> day;
//若day刚好等于一个完整月,则month++,若
if (day == dayTable[isLeapYear(year)][month]) {
day = 1;
month++;
if (month == 12) {
month = 1;
year++;
}
} else {
day++;
}
printf("%4d-%02d-%02d\n", year, month, day);
}
return 0;
}
9 XXX定律–浙江大学
描述:
对于一个数n,如果是偶数,就把n砍掉一半;如果是奇数,把n变成 3*n+ 1后砍掉一半,直到该数变为1为止。 请计算需要经过几步才能将n变到1,具体可见样例。
输入描述:
测试包含多个用例,每个用例包含一个整数n。(1<=n<=10000)
输出描述:
对于每组测试用例请输出一个数,表示需要经过的步数,每组输出占一行。
示例1
输入:
3
1
输出:
5
0
题解:
#include <iostream>
#include <cstdio>
using namespace std;
/**
* XXX定律--浙江大学
* @return
*/
int main() {
int n;
while (cin >> n) {
//计数
int count = 0;
while (n != 1) {
if ((n & 1) == 0) {
//n为偶数
n = n >> 1;
} else {
//n为奇数
n = 3 * n + 1;
n = n >> 1;
}
count++;
}
cout << count << endl;
}
return 0;
}