算法题--扔棋子

题目如下:“有一个100层高的大厦,你手中有两个相同的玻璃围棋子。从这个大厦的某一层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略,来得知那个临界层面。“先说下扩展:n层k个球

这道题有一个dp解,因存在递归。假设第一次扔在第r层,碎了就在1~r之间寻找,此时还剩k-1个球;没碎就在r+1~n之间寻找,还剩k个球。

代码如下:

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <string>
 5 #include <cmath>
 6 #include <iomanip>
 7 #include <vector>
 8 #include <deque>
 9 #include <list>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <algorithm>
14 #include <limits>
15 #include <utility>
16 #include <ctime>
17 #include <bitset>
18 using namespace std;
19
20 #define MAX_FLOOR 512
21 #define MAX_BALL  100
22
23 int dp(int n, int k)
24 {
25      if(k<1 || n<1) return -1;    //错误输入
26
27      if(k==1) return n-1;        //去掉一些trivial case
28      if(n==1) return 0;
29
30      int M[MAX_BALL][MAX_FLOOR];
31      int i,j,r;
32      int temp, min;
33
34      for(i=0;i<=k;i++) M[i][0]=M[i][1]=0;    //F(1,k)=F(0,k)=0
35      for(j=2;j<=n;j++) M[1][j]=j-1;            //F(n,1)=n-1
36
37      /*
38      状态转移方程:
39      F(n,k)=min{max{F(r,k-1)+1, F(n-r,k)+1}, 1<=r<=n}
40      */
41      for(i=2;i<=k;i++)
42          for(j=2;j<=n;j++)
43          {
44              min = numeric_limits<int>::max();
45              for(r=1;r<=j;r++)
46              {
47                  temp = max(M[i-1][r], M[i][j-r])+1;
48                  if(temp<min)
49                      min = temp;
50              }
51              M[i][j] = min;
52          }
53
54      return M[k][n];//F(n,k)
55  }
56
57  int main()
58  {
59      int n,k;
60
61      cin>>n>>k;
62      cout<<dp(n, k)<<endl;
63
64      return 0;
65  }

这道题对于第一问还有一个解:第一个球先找出临界层所在的段,第二个球从段中找层。由于找段的次数不可避免的会增加,那么就减少每次找层的次数。(其实我没太理解)

x+(x-1)+(x-2)....

算法题--扔棋子

时间: 2024-07-30 07:59:03

算法题--扔棋子的相关文章

(算法)扔棋子

题目: 1.有一个100层高的大厦,你手中有两个相同的玻璃围棋子.从这个大厦的某一层及更高的层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略(扔最少的次数),来得知那个临界层面. 2.如果大厦高度是N层,你有K个棋子,请问最少需要扔几次可以知道得临界层? 思路: 1.推导 这里不推倒,直接给出结论,具体推导参考:http://blog.csdn.net/jiaomeng/article/details/1435226 首先选择第x层扔第一个棋子q1: 如果棋子碎了,则在1~x-

笔试算法题(22):二分法求旋转数组最小值 &amp; 骰子值概率

出题:将一个数组最开始的k个(K小于数组大小N)元素照搬到数组末尾,我们称之为数组的旋转:现在有一个已经排序的数组的一个旋转,要求输出旋转数组中的最小元素,且时间复杂度小于O(N): 分析: 时间复杂度小于O(N)也就是不能用常规的遍历思路:可以将数组看成两个都是递增序列(假设为升序)的子数组,并且前半段的元素均大于等于后半段的元素,分界点的位于后半段数组的第一个元素就是最小元素: 具体算法:两个指针left和right指向数组第一个和最后一个元素,使用Binary Search确定中间元素mi

笔试算法题

转自:http://www.cnblogs.com/xwdreamer/archive/2011/12/13/2296910.html 1.把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向.   10  / \  6  14 / \ / \4  8 12 16 转换成双向链表4=6=8=10=12=14=16.  首先我们定义的二元查找树 节点的数据结构如下: struct BSTreeNode{  i

【软帝学院】12道java经典入门算法题!

12道java经典入门算法题! [程序1]   题目:将一个数组逆序输出. 程序分析:用第一个与最后一个交换. 其实,用循环控制变量更简单: for(int k=11;k>=1;k--) System.out.print(myarr[k]+","); [程序2]   题目:取一个整数a从右端开始的4-7位. 程序分析:可以这样考虑: (1)先使a右移4位. (2)设置一个低4位全为1,其余全为0的数.可用~(~0 < <4) (3)将上面二者进行&运算. pu

12道java经典入门算法题!

12道java经典入门算法题![程序1] ? 题目:将一个数组逆序输出. ? 程序分析:用第一个与最后一个交换. ? 其实,用循环控制变量更简单:for(int k=11;k>=1;k--)System.out.print(myarr[k]+","); [程序2] ? 题目:取一个整数a从右端开始的4-7位. ? 程序分析:可以这样考虑: ? (1)先使a右移4位. ? (2)设置一个低4位全为1,其余全为0的数.可用~(~0 < <4) ? (3)将上面二者进行&a

牛逼!一行代码居然能解决这么多曾经困扰我半天的算法题

春节假期这么长,干啥最好?当然是折腾一些算法题了,下面给大家讲几道一行代码就能解决的算法题,当然,我相信这些算法题你都做过,不过就算做过,也是可以看一看滴,毕竟,你当初大概率不是一行代码解决的. 学会了一行代码解决,以后遇到面试官问起的话,就可以装逼了. 一.2 的幂次方 问题描述:判断一个整数 n 是否为 2 的幂次方 对于这道题,常规操作是不断这把这个数除以 2,然后判断是否有余数,直到 n 被整除成 1 . 我们可以把 n 拆成二进制看待处理的,如果 n 是 2 的幂次方的话,那么 n 的

笔试算法题(09):查找指定和值的两个数 &amp; 构造BST镜像树

出题:输入一个已经升序排序的数组和一个数字:要求在数组中查找两个数,这两个数的和正好等于输入的那个数字,输出任意一对数字就可以,要求时间复杂度是O(n): 分析:对于升序排序的数组{-i-j-k-m--},只有可能是i+m=j+k(j和k可能是同一个数),所以可以从两边往中间收缩而忽视其他交叉相加的情况: 解题: 1 void FindSumFactor(int *array, int length, int sum) { 2 int left=0, right=length-1; 3 whil

笔试算法题(08):输出倒数第K个节点

出题:输入一个单向链表,要求输出链表中倒数第K个节点 分析:利用等差指针,指针A先行K步,然后指针B从链表头与A同步前进,当A到达链表尾时B指向的节点就是倒数第K个节点: 解题: 1 struct Node { 2 int v; 3 Node *next; 4 }; 5 Node* FindLastKth(Node *head, int k) { 6 if(head==NULL) { 7 printf("\nhead is NULL\n"); 8 exit(0); 9 } 10 Nod

笔试算法题(07):还原后序遍历数组 &amp; 半翻转英文句段

出题:输入一个整数数组,判断该数组是否符合一个二元查找树的后序遍历(给定整数数组,判定其是否满足某二元查找树的后序遍历): 分析:利用后序遍历对应到二元查找树的性质(序列最后一个元素必定是根节点,从左向右第一个比根节点大的元素开始直到根节点之前的所有元素必定在右子树,之前的所有元素必定在左子树): 解题: 1 bool PostOrderCheck(int *array, int i, int j) { 2 /** 3 * 如快速排序一样,解决小子文件 4 * */ 5 if(j-i+1 ==