1.一步之遥
从昏迷中醒来,小明发现自己被关在X星球的废矿车里。
矿车停在平直的废弃的轨道上。
他的面前是两个按钮,分别写着“F”和“B”。
小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。
按F,会前进97米。按B会后退127米。
透过昏暗的灯光,小明看到自己前方1米远正好有个监控探头。
他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。
或许,通过多次操作F和B可以办到。
矿车上的动力已经不太足,黄色的警示灯在默默闪烁…
每次进行 F 或 B 操作都会消耗一定的能量。
小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方1米远的地方。
请填写为了达成目标,最少需要操作的次数。
注意,需要提交的是一个整数,不要填写任何无关内容(比如:解释说明等)
答案:97
思路:我用的广搜,深搜应该也可以吧,但是个人感觉用广搜写简单省时间一点,因为求的是最优解。
#include<bits/stdc++.h>
using namespace std;
int ans=-1;
void bfs()
{
queue<pair<int,int> > q;
q.push({0,0});
while(!q.empty())
{
ans++;
pair<int,int> t=q.front();
q.pop();
if(t.second==1)
{
break;
}
if(t.second<0)
q.push({1,t.second+97});
else
q.push({-1,t.second-127});
}
}
int main()
{
int a=97,b=127;
bfs();
cout<<ans<<endl;
return 0;
}
2.随意组合
小明被绑架到X星球的巫师W那里。
其时,W正在玩弄两组数据 (2 3 5 8) 和 (1 4 6 7)
他命令小明从一组数据中分别取数与另一组中的数配对,共配成4对(组中的每个数必被用到)。
小明的配法是:{(8,7),(5,6),(3,4),(2,1)}
巫师凝视片刻,突然说这个配法太棒了!
因为:
每个配对中的数字组成两位数,求平方和,无论正倒,居然相等:
87^2 + 56^2 + 34^2 + 21^2 = 12302
78^2 + 65^2 + 43^2 + 12^2 = 12302
小明想了想说:“这有什么奇怪呢,我们地球人都知道,随便配配也可以啊!”
{(8,6),(5,4),(3,1),(2,7)}
86^2 + 54^2 + 31^2 + 27^2 = 12002
68^2 + 45^2 + 13^2 + 72^2 = 12002
巫师顿时凌乱了。。。。。
请你计算一下,包括上边给出的两种配法,巫师的两组数据一共有多少种配对方案具有该特征。
配对方案计数时,不考虑配对的出现次序。
就是说:
{(8,7),(5,6),(3,4),(2,1)}
与
{(5,6),(8,7),(3,4),(2,1)}
是同一种方案。
注意:需要提交的是一个整数,不要填写任何多余内容(比如,解释说明文字等)
答案:24
思路:刚开始的时候看了半天,不知道怎么去重,后来输出看了下,发现,它不考虑配对的顺序,那么一组数固定,全排列另一组就可以了。
#include<bits/stdc++.h>
using namespace std;
int a[10]={2,3,5,8};
int b[10]={1,4,6,7};
map<int,int> mp;
int check()
{
int sum1=0,sum2=0;
for(int i=0;i<4;i++)
{
int x=a[i]*10+b[i];
sum1+=x*x;
mp[x]++;
}
for(int i=0;i<4;i++)
{
int x=b[i]*10+a[i];
sum2+=x*x;
mp[x]++;
}
return sum1==sum2;
}
int main()
{
int ans=0;
do
{
if(check())
ans++;
}while(next_permutation(b,b+4));
cout<<ans<<endl;
return 0;
}
3.平方末尾
能够表示为某个整数的平方的数字称为“平方数”
比如,25,64
虽然无法立即说出某个数是平方数,但经常可以断定某个数不是平方数。
因为平方数的末位只可能是:[0, 1, 4, 5, 6, 9] 这6个数字中的某个。
所以,4325435332必然不是平方数。
如果给你一个2位或2位以上的数字,你能根据末位的两位来断定它不是平方数吗?
请计算一下,一个2位以上的平方数的最后两位有多少种可能性?
注意:需要提交的是一个整数,表示2位以上的平方数最后两位的不同情况数。
不要填写任何多余内容(比如,说明解释文字等)
答案:22
暴力就行了,注意去重
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
set<int> st;
for(int i=4;i<=10000;i++) //边界可以自己定,多试几个边界,看看结果一样不一样
{
ll x=(ll)i*i;
st.insert(x%100);
}
set<int>::iterator it;
for(it=st.begin();it!=st.end();it++) //最好输出一下看看自己做对没
cout<<*it<<" ";
cout<<endl<<st.size()<<endl;
return 0;
}
4.愤怒小鸟
X星球愤怒的小鸟喜欢撞火车!
一根平直的铁轨上两火车间相距 1000 米
两火车 (不妨称A和B) 以时速 10米/秒 相对行驶。
愤怒的小鸟从A车出发,时速50米/秒,撞向B车,
然后返回去撞A车,再返回去撞B车,如此往复…
两火车在相距1米处停车。
问:这期间愤怒的小鸟撞 B 车多少次?
注意:需要提交的是一个整数(表示撞B车的次数),不要填写任何其它内容。
答案:9
#include<bits/stdc++.h>
using namespace std;
int main()
{
double a=0,b=1000,t;
int flag=1,ans=0;
while(b-a>1)
{
t=(b-a)/60.0; //t表示此时到下次相撞需要的时间。因为方向相反,所以总体速度为60
a+=10*t;
b-=10*t;
if(flag) //flag为1的话表示此次和B相撞,所以一开始需给flag赋值为1
ans++;
flag=!flag; //下次撞的是另一边
}
cout<<ans<<endl;
return 0;
}
5.反幻方
我国古籍很早就记载着
2 9 4
7 5 3
6 1 8
这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。
下面考虑一个相反的问题。
可不可以用 1~9 的数字填入九宫格。
使得:每行每列每个对角线上的数字和都互不相等呢?
这应该能做到。
比如:
9 1 2
8 4 3
7 5 6
你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。
旋转或镜像算同一种。
比如:
9 1 2
8 4 3
7 5 6
7 8 9
5 4 1
6 3 2
2 1 9
3 4 8
6 5 7
等都算作同一种情况。
请提交三阶反幻方一共多少种。这是一个整数,不要填写任何多余内容。
答案:3120
思路:直接全排列就好了。注意最后结果需要除以8。(四种旋转,每种有两个镜像)
自己当时想的时候少算了两种情况,就想着4种旋转+2种镜像=6了。(难受qaq)
#include<bits/stdc++.h>
using namespace std;
int a[15]={1,2,3,4,5,6,7,8,9};
int vis[50];
int main()
{
int ans=0,x;
do
{
int flag=0;
memset(vis,0,sizeof(vis));
x=a[0]+a[1]+a[2];vis[x]++;
x=a[4]+a[5]+a[3];vis[x]++;
x=a[6]+a[7]+a[8];vis[x]++;
x=a[0]+a[3]+a[6];vis[x]++;
x=a[1]+a[4]+a[7];vis[x]++;
x=a[2]+a[5]+a[8];vis[x]++;
x=a[0]+a[4]+a[8];vis[x]++;
x=a[2]+a[4]+a[6];vis[x]++;
for(int i=1;i<=27;i++)
if(vis[i]>1)
{
flag=1;break;
}
if(!flag)
ans++;
}while(next_permutation(a,a+9));
cout<<ans/8<<endl;
return 0;
}
6.凑平方数
把0~9这10个数字,分成多个组,每个组恰好是一个平方数,这是能够办到的。
比如:0, 36, 5948721
再比如:
1098524736
1, 25, 6390784
0, 4, 289, 15376
等等…
注意,0可以作为独立的数字,但不能作为多位数字的开始。
分组时,必须用完所有的数字,不能重复,不能遗漏。
如果不计较小组内数据的先后顺序,请问有多少种不同的分组方案?
注意:需要提交的是一个整数,不要填写多余内容。
答案:300
思路:全排列+搜索
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[15]={0,1,2,3,4,5,6,7,8,9};
int cnt,ans;
ll res[15];
ll tem[15];
map<string,int> mp;
bool judge(ll x) //判断x是否为平方数
{
return x==(ll)sqrt(x)*(ll)sqrt(x); //注意必须要强制类型转换
}
void dfs(int x,int num)
{
if(x>10)
return;
if(x==10)
{
string s,ss;
for(int i=0;i<num;i++)
tem[i]=res[i];
sort(tem,tem+num); //用tem记录原来的数,排序是为了去重方便一些,因为题目说不计较顺序
for(int i=0;i<num;i++)
{
ss.clear();
ll xx=tem[i];
while(xx)
{
ss+=xx%10+'0';
xx/=10;
}
reverse(ss.begin(),ss.end()); //转置的原因是上面拼接的时候是倒着拼接的
s+=ss; //将找出来的完全平方数转化为字符串,拼接在一起
s+=','; //注意要使用字符将数字们分开
}
if(!mp[s]) //若已经算过,就不再算了
{
mp[s]=1;
ans++;
}
return;
}
if(a[x]==0) //一个数的开头不能为0,所以如果在开头,它只能单另作为一个数
{
res[num]=0;
dfs(x+1,num+1);
return;
}
ll t=0;
for(int i=x;i<=10;i++) //枚举与它身后的数字们结合是否能产生平方数
{
t=t*10+a[i];
if(judge(t))
{
res[num]=t;
dfs(i+1,num+1);
}
}
}
int main()
{
do
{
dfs(0,0);
}while(next_permutation(a,a+10));
cout<<ans<<endl;
return 0;
}
7.七星填数
如下图所示。
在七角星的14个节点上填入1~14 的数字,不重复,不遗漏。
要求每条直线上的四个数字之和必须相等。
图中已经给出了3个数字。
请计算其它位置要填充的数字,答案唯一。
填好后,请提交绿色节点的4个数字(从左到右,用空格分开)
比如:12 5 4 8
当然,这不是正确的答案。
注意:只提交4个用空格分开的数字,不要填写任何多余的内容。
答案:10 3 9 8
全排列
#include<iostream>
#include<algorithm>
using namespace std;
int a[20]={1,2,3,4,5,7,8,9,10,12,13};
int main()
{
do
{
int x1=a[0]+a[1]+a[2]+a[3];
int x2=a[0]+a[4]+a[6]+a[9];
int x3=6+a[1]+a[4]+14;
int x4=6+a[2]+a[5]+11;
int x5=a[3]+a[5]+a[7]+a[10];
int x6=14+a[6]+a[8]+a[10];
int x7=a[9]+a[8]+a[7]+11;
if(x1==x2 && x1==x3 && x1==x4 && x1==x5 && x1==x6 && x1==x7)
{
for(int i=0;i<11;i++)
cout<<a[i]<<" ";
cout<<endl;
}
}while(next_permutation(a,a+10));
return 0;
}
8.阶乘位数
9的阶乘等于:362880
它的二进制表示为:1011000100110000000
这个数字共有19位。
请你计算,9999 的阶乘的二进制表示一共有多少位?
注意:需要提交的是一个整数,不要填写任何无关内容(比如说明解释等)
答案:118445
思路:实际上是求log(9999!) = log(1 * 2 * 3 * 4… * 9999) = log(1)+log(2)+log(3)+…log(9999)
注意:以上求对数都是以2为底
#include<bits/stdc++.h>
using namespace std;
int main()
{
double ans=0;
for(int i=1;i<=9999;i++)
{
ans+=log(i*1.0)/log(2); //除以log(2)可以换底
}
cout<<ans<<endl; //注意最后要四舍五入
return 0;
}
9.拼棋盘
有 8x8 和 6x6 的棋盘两块(棋盘厚度相同,单面有棋盘,背面无图案)。参见【图1.png】
组成棋盘的小格子是同样大小的正方形,黑白间错排列。
现在需要一个10x10的大棋盘,希望能通过锯开这两个棋盘,重新组合出大棋盘。
要求:
1。 拼好的大棋盘仍然保持黑白格间错的特性。
2。 两个已有的棋盘都只允许锯一锯(即锯开为两块),必须沿着小格的边沿,可以折线锯开。
3。 要尽量保证8x8棋盘的完整,也就是说,从它上边锯下的那块的面积要尽可能小。
要求提交的数据是:4块锯好的部分的面积。按从小到大排列,用空格分开。
(约定每个小格的面积为1)
比如:10 10 26 54
当然,这个不是正确答案。
请严格按要求格式提交数据,不要填写任何多余的内容(比如,说明解释等)
额。。表示不会做…
10.打靶
小明参加X星球的打靶比赛。
比赛使用电子感应计分系统。其中有一局,小明得了96分。
这局小明共打了6发子弹,没有脱靶。
但望远镜看过去,只有3个弹孔。
显然,有些子弹准确地穿过了前边的弹孔。
不同环数得分是这样设置的:
1,2,3,5,10,20,25,50
那么小明的6发子弹得分都是多少呢?有哪些可能情况呢?
下面的程序解决了这个问题。
仔细阅读分析代码,填写划线部分缺失的内容。
#include <stdio.h>
#define N 8
void f(int ta[], int da[], int k, int ho, int bu, int sc)
{
int i,j;
if(ho<0 || bu<0 || sc<0) return;
if(k==N){
if(ho>0 || bu>0 || sc>0) return;
for(i=0; i<N; i++){
for(j=0; j<da[i]; j++)
printf("%d “, ta[i]);
}
printf(”\n");
return;
}
for(i=0; i<=bu; i++){
da[k] = i;
f(ta, da, k+1, _____________ , bu-i, sc-ta[k]*i); //填空位置
}
da[k] = 0;
}
int main()
{
int ta[] = {1,2,3,5,10,20,25,50};
int da[N];
f(ta, da, 0, 3, 6, 96);
return 0;
}
答案:i>0?ho-1:ho
枚举的是有几发一样的子弹从一个孔里面穿过去的,如果弹孔已经枚举完了,自然就不能枚举了,否则的话枚举下一个(ho-1)
11.打印数字
小明写了一个有趣的程序,给定一串数字。
它可以输出这串数字拼出放大的自己的样子。
比如“2016”会输出为:
22222 00000 1 6666
2 2 0 0 1 1 6
2 0 0 1 666666
2 0 0 1 6 6
2 0 0 1 6 6
2 2 0 0 1 6 6
2222222 00000 1111 66666
请仔细分析代码,填写划线部分缺少的内容。
#include <stdio.h>
#include <string.h>
#define ZIW 8
#define ZIH 7
void f(int n)
{
char cc[100];
int i,j;
char di[][ZIH][ZIW] =
{{" 00000 ",
“0 0”,
“0 0”,
“0 0”,
“0 0”,
“0 0”,
" 00000 “},
{” 1 ",
" 1 1 ",
" 1 ",
" 1 ",
" 1 “,
" 1 “,
" 1111”},
{” 22222 “,
“2 2”,
" 2”,
" 2 “,
" 2 “,
" 2 2”,
“2222222”},
{” 33333 “,
“3 3”,
" 3”,
" 3333 “,
" 3”,
“3 3”,
" 33333 “},
{” 44 ",
" 4 4 ",
" 4 4 ",
"4 4 ",
"4 4 ",
“4444444”,
" 4 “},
{” 55555 ",
" 5 ",
“555555 “,
" 5”,
" 5”,
“5 5”,
" 55555 “},
{” 6666 ",
"6 ",
"666666 ",
“6 6”,
“6 6”,
“6 6”,
" 66666 "},
{“7777777”,
"7 7 ",
" 7 ",
" 7 ",
" 7 ",
" 7 ",
" 7 “},
{” 88888 ",
“8 8”,
“8 8”,
" 88888 “,
“8 8”,
“8 8”,
" 88888 “},
{” 99999 “,
“9 9”,
“9 9”,
" 999999”,
" 9”,
“9 9”,
" 99999 "}};
sprintf(cc, “%d”, n);
for(i=0; i<ZIH; i++){
for(j=0; j<strlen(cc); j++){
printf("%s “, _______________________ ); //填空位置
}
printf(”\n");
}
}
int main()
{
f(2016);
return 0;
}
注意:只提交划线部分缺少的代码,不要添加任何题面已有代码或符号。
也不要提交任何说明解释文字等。
答案:di[cc[j]-‘0’][i]
12.棋子换位
有n个棋子A,n个棋子B,在棋盘上排成一行。
它们中间隔着一个空位,用“.”表示,比如:
AAA.BBB
现在需要所有的A棋子和B棋子交换位置。
移动棋子的规则是:
- A棋子只能往右边移动,B棋子只能往左边移动。
- 每个棋子可以移动到相邻的空位。
- 每个棋子可以跳过相异的一个棋子落入空位(A跳过B或者B跳过A)。
AAA.BBB 可以走法:
移动A = => AA.ABBB
移动B = => AAAB.BB
跳走的例子:
AA.ABBB = => AABA.BB
以下的程序完成了AB换位的功能,请仔细阅读分析源码,填写划线部分缺失的内容。
#include <stdio.h>
#include <string.h>
void move(char* data, int from, int to)
{
data[to] = data[from];
data[from] = ‘.’;
}
int valid(char* data, int k)
{
if(k<0 || k>=strlen(data)) return 0;
return 1;
}
void f(char* data)
{
int i;
int tag;
int dd = 0; // 移动方向
while(1){
tag = 0;
for(i=0; i<strlen(data); i++){
if(data[i]= =’.’) continue;
if(data[i]= =‘A’) dd = 1;
if(data[i]= =‘B’) dd = -1;
if(valid(data, i+dd) && valid(data,i+dd+dd)
&& data[i+dd]!=data[i] && data[i+dd+dd]==’.’){
//如果能跳…
move(data, i, i+dd+dd);
printf("%s\n", data);
tag = 1;
break;
}
}
if(tag) continue;
for(i=0; i<strlen(data); i++){
if(data[i]= =’.’) continue;
if(data[i]= =‘A’) dd = 1;
if(data[i]= =‘B’) dd = -1;
if(valid(data, i+dd) && data[i+dd]==’.’){
// 如果能移动…
if( ______________________ ) continue; //填空位置
move(data, i, i+dd);
printf("%s\n", data);
tag = 1;
break;
}
}
if(tag==0) break;
}
}
int main()
{
char data[] = “AAA.BBB”;
f(data);
return 0;
}
注意:只提交划线部分缺少的代码,不要复制已有代码或填写任何多余内容。