目录
感悟总结
这年的题总体感觉不难,只有三道编程大题,但一定要细心。
比如第一题,网友年龄,只要个数,第二题只要第一次开party的年龄。
dfs的题明显较多,第三题,第七题,第八题都可以用dfs来做
但第三题和第六题用实际上用全排列的套路更方便!第八题也需要用到全排列!
一、网友年龄(填空题)
某君新认识一网友。 当问及年龄时,他的网友说: “我的年龄是个2位数,我比儿子大27岁, 如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦. 请填写表示可能情况的种数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
问的是个数,一定要认真看题,一共有七种(代码显示的再加上题目的30岁)
下面的代码是从1开始枚举的,因为除了30不存在其他0的可能性!
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++){
int father=i*10+j;
int son=i+j*10;
if(father-son==27)
printf("%d\n",father);
}
return 0;
}//41 52 63 74 85 96
二、生日蜡烛(填空题)
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
两次for循环,一般年龄在50岁范围内就能找到答案,注意题目只要第一个结果,答案为26!
#include<bits/stdc++.h>
using namespace std;
int main(){
int sum;
for(int i=1;i<=50;i++){
for(int j=i;j<=50;j++){
sum+=j;
if(sum==236){
printf("%d %d",i,j);
break;
}
}
sum=0;
}
return 0;
}//运行结果26 33
三、方格填数(填空题)
如下的10个格子
填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
这道题可以用全排列+判断,也可以用dfs+剪枝
全排列(递归)
#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int ans;
bool check(){
if(abs(a[0]-a[1])==1||abs(a[0]-a[3])==1||abs(a[0]-a[4])==1||abs(a[0]-a[5])==1
||abs(a[1]-a[2])==1||abs(a[1]-a[4])==1||abs(a[1]-a[5])==1||abs(a[1]-a[6])==1
||abs(a[2]-a[5])==1||abs(a[2]-a[6])==1
||abs(a[3]-a[4])==1||abs(a[3]-a[7])==1||abs(a[3]-a[8])==1
||abs(a[4]-a[5])==1||abs(a[4]-a[7])==1||abs(a[4]-a[8])==1||abs(a[4]-a[9])==1
||abs(a[5]-a[6])==1||abs(a[5]-a[8])==1||abs(a[5]-a[9])==1
||abs(a[6]-a[9])==1
||abs(a[7]-a[8])==1
||abs(a[8]-a[9])==1)
return false;
return true;
}
//全排列的套路
void f(int k){
if(k==10)
{//递归出口
if(check()) ans++;
return ;
}
for(int i=k;i<10;i++)//尝试位置i宇位置k交换,以此确定k位
{
int t=a[i];
a[i]=a[k];
a[k]=t;
f(k+1);
//回溯
int t=a[i];
a[i]=a[k];
a[k]=t;
}
}
int main(){
f(0);
cout<<ans<<endl;
return 0;
}
//运行结果:1580
一般还是推荐这种全排列,速度比递归快一些
#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int ans;
bool check(){
if(abs(a[0]-a[1])==1||abs(a[0]-a[3])==1||abs(a[0]-a[4])==1||abs(a[0]-a[5])==1
||abs(a[1]-a[2])==1||abs(a[1]-a[4])==1||abs(a[1]-a[5])==1||abs(a[1]-a[6])==1
||abs(a[2]-a[5])==1||abs(a[2]-a[6])==1
||abs(a[3]-a[4])==1||abs(a[3]-a[7])==1||abs(a[3]-a[8])==1
||abs(a[4]-a[5])==1||abs(a[4]-a[7])==1||abs(a[4]-a[8])==1||abs(a[4]-a[9])==1
||abs(a[5]-a[6])==1||abs(a[5]-a[8])==1||abs(a[5]-a[9])==1
||abs(a[6]-a[9])==1
||abs(a[7]-a[8])==1
||abs(a[8]-a[9])==1)
return false;
return true;
}
//全排列的套路
int main(){
do{
if(check()) ans++;
}
while(next_permutation(a,a+10));
cout<<ans<<endl;
return 0;
}//运行结果:1580
四、快速排序(代码补充)
排序在各种场合经常被用到。 快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”, 用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。 再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r)
{
int i = p;
int j = r + 1;
int x = a[p];
while(1){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,j);
}
___swap(a,p,j)_____;//代码补充
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
quicksort(a,p,q-1);
quicksort(a,q+1,r);
}
}
int main()
{
int i;
int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
int N = 12;
quicksort(a, 0, N-1);
for(i=0; i<N; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
这道题在quicksort函数里q-1,q+1的位置明显说明以中间的q做了分割,而q则是partition函数里返回的j,这个j应该代表的就是一开始的标尺X,但如果直接将x赋值给a[j],会直接覆盖原本的a[j]的值,正确的代码是调用程序中的函数swap,填写结果为swap(a,p,j)!
五、消除尾一(代码补充)
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
如果最后一位是0,则原数字保持不变。
如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000
00000000000000000000000000001100 00000000000000000000000000001100
请仔细阅读程序,填写划线部分缺少的代码。
#include <stdio.h>
void f(int x)
{
int i;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf(" ");
x = ____x&(x+1)______;//代码补充
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
六、 寒假作业(填空题)
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
和方格填数思路一模一样,但13!太大,需要等待较长时间,可以提前剪枝(注释部分),不剪枝的话需要运行1分多钟
#include<bits/stdc++.h>
using namespace std;
int a[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
int ans;
bool check(){
if(a[0]+a[1]==a[2]&&a[3]-a[4]==a[5]
&&a[6]*a[7]==a[8]&&a[9]%a[10]==0&&a[9]/a[10]==a[11])
return true;
return false;
}
void f(int k)
{
if(k==13)
{
if(check()) ans++;
return ;
}
for(int i=k;i<13;i++)
{
int t=a[i];
a[i]=a[k];
a[k]=t;
/*if((k==2&&a[0]+a[1]!=a[2])||(k==5&&a[3]-a[4]!=a[5]))
{
{
int t=a[i];
a[i]=a[k];
a[k]=t;
}
continue;
}*/ //提前剪枝,加快速度
f(k+1);
int t=a[i];
a[i]=a[k];
a[k]=t;
}
}
int main(){
f(0);
cout<<ans<<endl;
return 0;
}//运行结果:64
第二种全排列
#include<bits/stdc++.h>
using namespace std;
int a[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
int ans;
bool check(){
if(a[0]+a[1]==a[2]&&a[3]-a[4]==a[5]
&&a[6]*a[7]==a[8]&&a[9]%a[10]==0&&a[9]/a[10]==a[11])
return true;
return false;
}
int main(){
do{
if(check())
ans++;
}while(next_permutation(a,a+13));
cout<<ans<<endl;
return 0;
}
七、剪邮票(填空题)
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。 (仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
单纯dfs解决不了T型问题,正确思路一个是枚举所有的5张的可能,再检查是不是连通块!
#include<bits/stdc++.h>
using namespace std;
int maze[3][4]={0,0,0,0,0,0,0,0,0,0,0,0};
int a[12]={0,0,0,0,0,0,0,1,1,1,1,1};
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
int ans=0;
void dfs(int x,int y){
if(x>2||x<0||y>3||y<0) return;
if(maze[x][y]==0) return;
maze[x][y]=0;
for(int i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
dfs(xx,yy);
}
}
bool check(int a[12])
{
int k=0;
int x,y;
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
if(a[k]==1)
{
x=i;
y=j;
}
maze[i][j]=a[k++];
}
}
dfs(x,y);
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(maze[i][j]==1) return false;
}
}
return true;
}
int main()
{
do{
if(check(a)) ans++;
}while(next_permutation(a,a+12));
cout<<ans<<endl;
return 0;
} //运行结果116
八、 四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序: 0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
暴力枚举
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a,b,c,d;
a=n;
for (int i=0;i<=sqrt(a);i++) {
int b=a-i*i;
for (int j=0;j<=sqrt(b);j++) {
int c=b-j*j;
for (int k=0;k<=sqrt(c);k++) {
int d=c-k*k;
int l=sqrt(d);
if (l*l==d) {
printf("%d %d %d %d\n",i,j,k,l);
exit(0);
}
}
}
}
return 0;
}
九、密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是: 给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABECDCBABC
则程序应该输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
动态规划
在这里插入代码片
十、 最大比例
X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式:
第一行为数字N(n<100),表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额
要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数
测试数据保证了输入格式正确,并且最大比例是存在的。
例如,输入:
3
1250 200 32
程序应该输出:
25/4
再例如,输入:
4
3125 32 32 200
程序应该输出:
5/2
再例如,输入:
3
549755813888 524288 2
程序应该输出:
4/1
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。 所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意:
所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
一开始就没读懂题,原来随机调查了一些获奖者的奖金数的意思,就是要从那些里面随便选几个数出来,额。。。,过段时间补代码!