目录
1、年龄巧合
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明和他的表弟一起去看电影,有人问他们的年龄。小明说:今年是我们的幸运年啊。我出生年份的四位数字加起来刚好是我的年龄。表弟的也是如此。已知今年是 2014年,并且,小明说的年龄指的是周岁。
请推断并填写出小明的出生年份。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
刷题思路:
周岁表示年龄时,出生年份为0岁,年龄=当前年份-出生年份
从2013开始从后往前枚举,当找到一个i的各位数字之和等于年龄(2014-i)的数 后输出。
注意:第一个得到的数是表弟的出生日期,第二个得到的数才是小明的出生日期。
代码:
#include<bits/stdc++.h>
using namespace std;
int f(int x){//返回每位数字之和
int sum=0;
while(x){
sum+=x%10;
x/=10;
}
return sum;
}
int main(){
int n=0;//记录是第几个满足条件的年龄
for(int i=2013;;i--){
if(f(i)==2014-i){
n++;
if(n==2) cout<<i;
}
}
return 0;
}
2、纸牌三角形
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
A,2,3,4,5,6,7,8,9 共 9 张纸牌排成一个正三角形(A 按 1 计算)。要求每个边的和相等。 下图就是一种排法。
这样的排法可能会有很多。
如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?
请你计算并提交该数字。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
刷题思路:
这题我使用dfs枚举全排列(使用y总的模板改写)后再进行条件判断求解;
题目规定旋转、镜像算一种排法,而每一种组合旋转后有3类,镜像后有2类,总共可获得6种不同类型 ,所以最终结果需要除6;
这题在c++中也可以使用STL的next_permutation;
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=10 ;
int ans=0;
int p[N];//p[1]~p[9]存放1~9的全排列
bool vis[N];//标记是否已访问
void dfs(int u){
if(u>9){
int a=p[1]+p[2]+p[3]+p[4];
int b=p[4]+p[5]+p[6]+p[7];
int c=p[7]+p[8]+p[9]+p[1];
if(a==b&&a==c){
ans++;
}
return;
}
for(int i=1;i<=9;i++){//枚举1~9全排列
if(!vis[i]){
p[u]=i;
vis[i]=1;
dfs(u+1);
vis[i]=0;
p[u]=0;
}
}
}
int main(){
dfs(1);
cout<<ans/6;
return 0;
}
递归实现排列型枚举
题目描述:
把 1∼n这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式
一个整数 n。
输出格式
按照从小到大的顺序输出所有方案,每行 1 个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围
1≤n≤9
输入
3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
排列型枚举y总模板 (来自acwing)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=15 ;
bool vis[N];//表示是否被访问
int p[N];//记录排列的方案
int n;
void dfs(int u){
if(u>n){//空位填满
for(int i=1;i<=n;i++){//输出方案
cout<<p[i]<<" ";
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){//枚举每个空可以填什么数
if(!vis[i]){//如果数字i未被用过
vis[i]=1;//标记i已使用
p[u]=i;//放入空位
dfs(u+1);//填下一个空位
vis[i]=0;//回溯
}
}
}
int main(){
cin>>n;
dfs(1);
return 0;
}
3、取球游戏
题目描述
今盒子里有 n 个小球,A、B 两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断。
我们约定:
每个人从盒子中取出的球的数目必须是:1,3,7 或者 8 个。轮到某一方取球时不能弃权!A 先取球,然后双方交替取球,直到取完。被迫拿到最后一个球的一方为负方(输方)
请编程确定出在双方都不判断失误的情况下,对于特定的初始球数,A 是否能赢?
输入描述
先是一个整数 n(n<100),表示接下来有 n个整数。
然后是 n 个整数,每个占一行(整数),表示初始球数。
输出描述
程序则输出 n 行,表示 A 的输赢情况(输为 0,赢为 1)。
输入输出样例
输入
4
1
2
10
18
输出
0
1
1
0
博弈论问题
本人使用st[ ]数组记录状态,st[ ]=1为A胜利,st[ ]=0为A失败,下标表示球的个数
当A到最后只有一个球时为必败状态(st[1]=0),所以当球数为1+1 1+3 1+7 1+8时代表A可分别取1,3,7,8个球,使后手只有一个球能取,A成为先手必胜状态(st[2]=st[4]=st[8]=st[9]=1),所以A的所有必败状态加上1,3,7,8后都变为A的必胜状态。因此可以从一个球开始进行判断,若为必败状态,可推出之后的+1,+3,+7,+8为必胜状态,一直枚举到达到球的总数 x,再判断此时状态是必胜状态(st[x]=1)还是必败态(st[x]=0)
先手必胜状态和先手必败状态:
先手必胜状态 : 先手行动以后,可以让剩余的状态变成必败状态留给对手
先手必败状态 : 与先手必胜相对,不管怎么操作,剩余的状态都是对手的必胜状态
即我方的必败状态
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e4+10 ;
int n;
int a;
int st[N];
int f(int x){
memset(st,0,sizeof(st));
for(int i=1;i<=x;i++){
if(st[i]==0){//当st[1]==0即为a到最后只有一个球能取时的必输情况
st[i+1]=st[i+3]=st[i+7]=st[i+8]=1;
}
}
return st[x];
}
int main(){
cin>>n;
while(n--){
cin>>a;
cout<<f(a)<<endl;
}
return 0;
}