ZJYYOJ LZY去年买了个表(dfs)[C++]

题目及翻译

题面

LZY去年买了个表,很神奇,是个二进制手表。如下图所示
下图例如,上面的二进制手表读取 “3:25”。
输入一个非负整数 n 代表当前 LED 亮着的数量,输出所有可能的时间。
结果按字典序排列

输入

测试数据由多组测试样例组成。每组测试样例第一行输入一个整数 n ( 0 <= n <= 8 )

输出

输出所有可能的时间组合

输入样例

1

输出样例

0:01
0:02
0:04
0:08
0:16
0:32
1:00
2:00
4:00
8:00

提示

1.小时不会以零开头,比如 “01:00” 是不允许的,应为 “1:00”。
2.分钟必须由两位数组成,可能会以零开头,比如 “10:2” 是无效的,应为 “10:02”。
3.输出顺序按照字典序从小到大排序

题目思路

给学弟学妹写篇题解,小不点们加油!!
有不懂的地方欢迎留言或者微信找我询问~
写dfs的时候看题目,陷入了迷惑,竟然没有发现它是个水题,刚打完领悟了。
这tm不是两个for预处理跑一下吗?!
不过既然用来练递归,那还是用递归的写法吧
题目意思很简单,有时针和分针(时点和分点)
时针用1 2 4 8 组合之和表示,分针用1 2 4 8 16 32 组合之和表示
本来我的思路是模拟这个时钟走的方式,后来想到用两个数的二进制模拟时针和分针
那么只需要统计这两个数的二进制上有几个1,加起来是否刚好为n,就行了
每个数二进制上1的个数就代表了其所需的灯数
比如: 9的二进制是1001 亮的灯是1和8,而二进制1001就是其亮灯本来的原理
这题麻烦的是字典序排序,我用vector存string实现的,格式化那里偷懒用了一下sprintf
不会的小朋友可以去自学或者找师父父~

注意事项

退出递归的条件是时间超过11点
这题分析样例就可得出,只有0到11点,0到59分
递归中增加时间,判断退出,计算答案的顺序是固定的,如果改了可能导致0分0秒之类的样例错误

AC代码

C++

用时4MS 内存2036K 长度1283B

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n;
vector<string> res; //储存答案
void toTime(int hour,int minute){//时间转字符串
	char s[5];
	sprintf(s,"%d:%02d",hour,minute);//sprintf格式化到字符串s
	string str = s;//把s转化为string
	res.push_back(str);//存入res
}
int cal(int x){//统计x的二进制上1的个数
	int num = 0;
	while(x > 0){
		num += x & 1;//x & 1 相当于 x % 2,但是位运算更快
		x >>= 1;//x >>= 1 相当于x /= 2,但是位运算更快
	}
	return num;
}
void dfs(int hour,int minute){//搜索每个小时的每一分钟
	if(hour == 12)return;//时间到12点就结束了
	if(cal(hour) + cal(minute) == n)toTime(hour,minute);//如果二进制上的1的个数和刚好等于n,记录答案
	++minute;//增加1分钟
	if(minute == 60){//如果到了60分钟,则改为增加一小时
		minute = 0;
		++hour;
	}
	dfs(hour,minute);//递归
} 
int main(){
	while(cin>>n){//输入到文件尾
		res.clear();//清空答案数组
		dfs(0,0);//从0分0秒开始搜索
		sort(res.begin(),res.end());//利用string可以直接字典序比较的特性,字典序排序
		for(int i=0;i<res.size();++i){//遍历输出答案
			cout<<res[i]<<endl;
		}
	}
	return 0;
}

本文作者 CSDN@扶她小藜
个人主页链接 https://blog.csdn.net/weixin_44579869

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值