290 likes | 429 Views
习题选 讲(分治法). 递归与分 治. Rate of Return Binary Tree sicily 1935. 二叉树重建 电路 稳定性 Monthly Expense Pie sicily 1028. Hanoi Tower Sequence 1211 商人的宣传 1071 Floors. 1017 Rate of Return. 解题思路: 当利润率在 [0,1] 之间,假设投资额和时间不变,则利润率越高,最后的本金和利润总和越大。
E N D
递归与分治 • Rate of Return • Binary Tree • sicily1935. 二叉树重建 • 电路稳定性 • Monthly Expense • Pie • sicily 1028. Hanoi Tower Sequence • 1211 商人的宣传 • 1071 Floors
1017 Rate of Return • 解题思路: • 当利润率在[0,1]之间,假设投资额和时间不变,则利润率越高,最后的本金和利润总和越大。 • 因此对利润率进行二分查找,检查在假设的利润率下,比较最后的本金和利润总和与实际值,调整二分上下界,直到达到某个精度。
1017 Rate of Return • double find(double left,double right,int m,double x) • { • double center,s=0; • center=(left+right)/2; • if (right-left<=0.000000005) • return center; • for (int i=1;i<=m;i++) • s+=a[i]*pow(1.0+center,m+1-i); • if (s<x) • return find(center,right,m,x); • else • return find(left,center,m,x); • }
Binary Tree Given a binary tree, every node of which contains one upper case character (‘A’ to ‘Z’); you just need to print all characters of this tree in pre-order. Input: 4 C 1 0表示标志符为4的点,点值为C,其左儿子为标识符为1的点,没有右孩子。3 4 C 1 3 1 A 0 0 3 B 0 0 Output: CAB
二叉树重建 • 题目大意: • 输入一棵二叉树的先序遍历序列和中序遍历序列,输出它的广度优先遍历序列。 • 例如,先序ABCDEF,中序CBAEDF
C D E F 二叉树重建 • 解题思路 • 前序遍历,根节点最先被输出,所以A是根结点。中序遍历,左子树的全部结点输出后,接着输出根结点,最后输出右子树的全部结点。 • 例如,先序ABCDEF,中序CBAEDF A B
B C D E F E C F E F B C D D 二叉树重建 • 左子树:前序BC,中序CB • 右子树:前序DEF,中序EDF A A A B
二叉树重建 void build(int n, intdep, char* s1, char* s2) { if (n <= 0) return; int p = strchr(s2, s1[0]) - s2; lv[dep][ln[dep]++] = s1[0]; build(p, dep+1, s1+1, s2); build(n-p-1, dep+1, s1+p+1, s2+p+1); } 调用:build(strlen(s1), 0, s1, s2);
电路稳定性 • 题目大意: • 给出一个电路,以及各元件断路的概率。求整个电路断路的概率。
电路稳定性 • 解题思路: • n个元件,若它们的断路概率为p1,p2,...,pn,则串联断路概率为1-(1-p1)(1-p2)...(1-pn),并联断路概率为p1p2...pn。 • 问题的关键点是把字符串表示的电路转化为实际电路。 • http://222.200.182.58/viewsource.php?sid=87438
Monthly Expense • 题目大意: • 农夫知道未来N天每天的花费,他现在需要把这N天分成连续的M段,使得花费最大的段花费最小。求这个花费。 • 1 <= N <= 100,000,1 <= M <= N
Monthly Expense • 解题思路: • 二分最高花费,再使用贪心的方法求出在这个花费下是否能把N天分成M段且每段都不超过这个花费,从而调整二分的上下界。
Monthly Expense • while(min<=max){ • mid=(min+max)/2; • int t=0;int num=0; • for(i=0;i<n;i++){ • if(num+N[i]<=mid)num+=N[i]; • else {t++; • if(t>m)break; • num=N[i];} • } • if(num)t++; • if(t<=m){ • ans=mid; • max=mid-1; • } • else min=mid+1; • }
Pie • 题目大意: • 一共有N个派和F+1个人,每个人分到一份派,要求每个人分到的派的大小相等,问最大的面积是多少。 • 1 ≤ N, F ≤ 10 000
Pie • 解题思路: • 二分派的大小,再使用贪心的方法求出在这个大小下,是否足够分给所有人,从而调整二分的上下界。
Pie • while(max-min>1e-5){ • mid=(min+max)/2.0; • int sum=0; • for(i=0;i<n;i++) • sum+=(int)(N[i]/mid); • if(sum<f) • max=mid; • else • min=mid; • }
1028 Hanoi Tower Sequence • 题目大意: • 定义汉诺塔,共有三个柱子和很多的大小两两不同的盘子放在一个柱子上,要求把它们移到另一个柱子上,每次只能移动一个放在柱子最顶端的盘子,并且每次移动后需保证较小的盘子在较大的盘子上面。给出步数p,求第p步移动的盘子的大小。 • p<=10^100
1028 Hanoi Tower Sequence • 解题思路: • n个盘子的汉诺塔问题递归求解:把前n-1个盘子移到第二根柱子上,把第n个盘子移到第三根柱子上,把前n-1个盘子移到第三根柱子上。 • 从一根柱子到另一根柱子,移动1个盘子需要f(1)=1步,移动k(k>1)个盘子需要f(k)=f(k-1)+1+f(k-1)步。 • 即得到f(k)=2^k-1。因此第2^k步移动的是k+1个盘子。在移动第k+1个盘子后,左右对移地移动k个盘子。
1028 Hanoi Tower Sequence • 把p化成二进制数,假设现在p里有超过1个位为1,设最高位为k,则在2^k步前和2^k步后对称,因此第p步移的盘子与第p-2^k步移的盘子一样。 • 直到p里只有1个位为1,设此时p=2^m,则此步移动的是第m+1个盘子。 • 因此题目转化成二进制数p,从低位起连续0的位数,加1,为答案。
1028 Hanoi Tower Sequence • int cal(int a[],int n) { • int cnt=1; • while (a[n-1]%2==0) { • cnt++; • for (int i=0,temp=0;i<n;i++) { • temp=temp*10+a[i]; • a[i]=temp/2; • temp%=2; • } • } • return cnt; • }
1211 商人的宣传 • 题目大意: • 有n个州,m条单向边,规定天数为L。 • 共有q个询问,每个询问为从州A到州B刚好为L步的方案数。
1211 商人的宣传 • 解题思路: • 第0天,每个州到自己的方案数为1。 • 第n+1天,每个州A到另一个州B的方案数为,对所有州C,第n天从A到C的方案数与一天内从C到B的方案数的积,再对所有州求和。(即第n天通过州C作中转的方案)
1211 商人的宣传 • int cal(int A,int B) { • int i,j,k; • memset(ans,0,sizeof(ans)); • ans[0][A][A]=1; • for (k=1;k<=L;k++) { • for (i=1;i<=n;i++) • for (j=1;j<=n;j++) • ans[k][A][i]+=ans[k-1][A][j]*edge[j][i]; • return ans[L][A][B]; • }
1071 Floors • 题目大意: • 一块长方形地板是由很多长方形瓷砖组成的,每次可以从中选一块,沿着瓷砖的边缘按直线切成两块,直到没有任何块可以继续此操作。求出此时最大的块的面积。
1071 Floors • 解题思路: • 对于每一块,尝试平行于长方形的两边分别切割。对于分出来的小块,递归进行重复操作。 • 判断是否可切割:按垂直于切割方向对瓷砖进行排序,切割线所切出来的块的面积与所在一侧的瓷砖总面积之和相等,则可切割。
1071 Floors • void cal(int x1,int y1,int x2,int y2,int l,int r) { • int s=(x2-x1)*(y2-y1); • if (s<=ans) • return; • if (cutx(x1,y1,x2,y2,l,r)) • return; • if (cuty(x1,y1,x2,y2,l,r)) • return; • if (s>ans) • ans=s; • }
1071 Floors • bool cmpx(const rect &a,const rect &b) { return a.xl<b.xl; } • bool cutx(int x1,int y1,int x2,int y2,int l,int r) { • sort(a+l,a+r+1,cmpx); • int x=x1,s=0; • for (i=l;i<r;i++) { • s+=a[i].s; • if (a[i].xh>x) x=a[i].xh; • if (s==(x-x1)*(y2-y1)) { • cal(x1,y1,x,y2,l,i); • cal(x,y1,x2,y2,i+1,r); • return true; • } • } • return false; • }