AOJ 794.西瓜理发记(二)
Time Limit: 1000 ms Case Time Limit: 1000 ms Memory Limit: 64 MB
Total Submission: 151 Submission Accepted: 28Description剃完光头后,西瓜表示非常开心,于是直接骑上自行车去往勺林寺。
等骑到勺林寺的时候,头发已经都长出来了,于是西瓜决定在附近的理发店再剃一次。
然而这里的理发店老板WzyJerry表示正在做ACM练习,没空给他理发。
西瓜决定帮助老板AK。
题目是这样的:
你现在有一个培养盒,盒中没有细菌
每天早上,你可以向盒中放入一个细菌
每天晚上,一个细菌会分裂成两个。
求如果你想在将来的某天使盒中恰好有n个细菌,你最少要向盒中放入几个细菌
Input输入数据包含多组
每组一个整数n(1≤n ≤10^9)
Output每组数据输出一个整数x,表示最少需要放入的细菌个数
Sample Input
Original Transformed 5 1
Sample Output
Original Transformed 2 1
提供两种思路
- 模拟
- 位运算(2进制)
模拟(被注释部分)
使用DFS来模拟操作。
从1个细菌开始
早上分别选择放入细菌和不放入细菌,而后与要求匹配,查看是否符合
晚上在两种情况下分别将细菌乘2,继续DFS
这种方法比较直观,代码也很简单,但是效率非常低,需要将树的所有分支都遍历至n,而树有2n个叶,也即时间效率为O(2n)
位运算(2进制)
由模拟算法,我们发现时间效率与2n有关系,因此,可以比较容易想到2进制的算法。
早上是否放入,可看做最低位是否为1;晚上乘2可看作左移一位(<<1)。
由于得到n个细菌是唯一的,所以n(2)中的1的个数为最优解,也是唯一解。
因此,只需判断n(2)中的1的个数即可。
该算法的效率只和n的二进制位数有关时间效率为O(n),并且采用二进制运算,每次运算量也非常小。
1 #include <cstdio> 2 #include <string> 3 #include <cstring> 4 #include <cmath> 5 #include <memory> 6 #include <stack> 7 #include <queue> 8 #include <set> 9 #include <algorithm> 10 #include <map> 11 #include <vector> 12 using namespace std; 13 14 #define debug 0 15 16 /* 17 By:OhYee 18 Github:OhYee 19 Email:oyohyee@oyohyee.com 20 Blog:http://www.cnblogs.com/ohyee/ 21 22 かしこいかわいい? 23 エリーチカ! 24 要写出来Хорошо的代码哦~ 25 */ 26 27 int N; 28 /* 29 30 int ans=999999; 31 void DFS(int n,int cnt){ 32 //printf("%d %d\n",n,cnt); 33 if(n==N) 34 ans=min(cnt,ans); 35 if(n+1==N) 36 ans=min(cnt+1,ans); 37 if(n>N) 38 return ; 39 DFS(2*n,cnt); 40 DFS(2*(n+1),cnt+1); 41 return; 42 } 43 */ 44 int niconiconi(int n){ 45 int cnt; 46 for(cnt=0;n;n>>=1) 47 cnt+=(n&1); 48 return cnt; 49 } 50 51 bool Do(){ 52 if(scanf("%d",&N)==EOF) 53 return false; 54 //ans=999999; 55 //DFS(1,1); 56 printf("%d\n",niconiconi(N)); 57 } 58 59 60 61 int main(){ 62 #if debug 63 freopen("in.txt","r",stdin); 64 #endif 65 while(Do()); 66 return 0; 67 }
然而,我并不能保证我说的是对的。请自行验证,如有错误,请指正
新博客地址
https://www.oyohyee.com
https://www.oyohyee.com