木棒问题

题目描述XX有n根长度不同的木棒,有一天它把所有的木棒排成一行,用S1,S2,S3,...,Sn表示.量出每个木棒的长度Sk(1<=k<=n),它发现有两个木棒Si和Sj(1< = i < j < = n),它们之间的所有木棒都比Si要长比Sj短.
现在给出每个木棒的长度,你需要找到满足上述条件的两个木棒Si和Sj,使得j-i最大. (请使用分治法解此题)。

解题思路:我是用的RMQ方法来找到一段区间的最小值和最大值,预处理复杂度为O(nlogn),以后查找任意区间最小值(最大值)复杂度为O(logn)。RMQ方法是动态规划rmq[i][j]表示以i开始的长度为2^j的区间的最小值(最大值),将该区间等分为两个部分,两部分区间最小值(最大值)的最小值(最大值)即为该区间的最小值(最大值)。具体见代码。

递归部分思路很清晰,一个思路是,找到一个区间最小值、最大值的位置然后分为三个区间,设最小值位置为l,最大值位置为r,若l<r,那么很显然中间一段j-i最大值为r-l,两端区间递归下去,若r<l,那么三段区间都要递归下去,若l=r,返回-1,说明没找到满足情况的。

一个思路是,设置一个ans为全局变量,这个值就是最后j-i的最大值,这样方便剪枝,思路其实和前一种基本类似。

第一种思路的全部代码:

View Code
  1 #include<iostream>
2 using namespace std;
3 int n;
4 int num[50000];
5 int rmq1[50000][15], rmq2[50000][15]; // rmq[i][j]表示从i开始长为2^j的区段中最小值的位置
6 int Min(int a, int b)
7 {
8 return num[a] < num[b] ? a : b;
9 }
10 int Max(int a, int b)
11 {
12 return num[a] > num[b] ? a : b;
13 }
14 // 初始化rmq数组
15 void InitRMQ()
16 {
17 int i, j;
18 for (i = 0; i < n; i ++)
19 {
20 rmq1[i][0] = i;
21 rmq2[i][0] = i;
22 }
23 //动态规划解法
24 for (i = 1; (1<<i)<= n; i ++)
25 {
26 for (j = 0; j < n; j ++)
27 {
28 rmq1[j][i] = rmq1[j][i-1];
29 rmq2[j][i] = rmq2[j][i-1];
30 if (j + (1<<(i-1)) < n)
31 {
32 rmq1[j][i] = Min(rmq1[j][i], rmq1[j+(1<<(i-1))][i-1]); //从j开始长为2^i的区间等分为两段,取两段区间最小值的最小值
33 rmq2[j][i] = Max(rmq2[j][i], rmq2[j+(1<<(i-1))][i-1]); //从j开始长为2^i的区间等分为两段,取两段区间最大值的最大值
34 }
35 }
36 }
37 }
38 // 查询下标从f到t的这一段数中(包含f和t)的最小值.
39 // 返回最小值的下标
40 int QueryMin(int f, int t)
41 {
42 if(f == t)
43 return f;
44 int i;
45 int l = t - f + 1;
46 for (i = 0; (1<<(i+1))<=l; i ++);
47 return Min(rmq1[f][i], rmq1[t-(1<<i)+1][i]);
48 }
49 int QueryMax(int f, int t)
50 {
51 if(f == t)
52 return f;
53 int i;
54 int l = t - f + 1;
55 for (i = 0; (1<<(i+1))<=l; i ++);
56 return Max(rmq2[f][i], rmq2[t-(1<<i)+1][i]);
57 }
58 int solve(int l, int r){
59 if(l >= r)
60 return -1;
61 int m1, m2, a, b;
62 m1 = QueryMin(l,r);
63 m2 = QueryMax(l,r);
64 if(m1 == m2)
65 return -1;
66 int ans = -1;
67 if(m1 < m2){
68 ans = m2 - m1;
69 if(m1-l-1 > ans){
70 a = solve(l,m1-1);
71 if(a > ans)
72 ans = a;
73 }
74 if(r - m2 -1 > ans){
75 b = solve(m2+1,r);
76 if(b > ans)
77 ans = b;
78 }
79 }
80 else{
81 ans = solve(l,m2);
82 if(r - m1 > ans){
83 b = solve(m1,r);
84 if(b > ans)
85 ans = b;
86 }
87 if(m1-m2-2 > ans){
88 a = solve(m2+1,m1-1);
89 if(a > ans)
90 ans = a;
91 }
92 }
93 return ans;
94 }
95 int main(){
96 while(scanf("%d", n) == 1){
97 int i;
98 for (i = 0; i < n; i ++)
99 scanf("%d", &num[i]);
100 InitRMQ();
101 printf("%d\n",solve(0,n-1));
102 }
103 return 0;
104 }

第二种思路递归部分代码,其余同上(ans为全局变量):

View Code
 1 void solve(int l, int r, int lastl, int lastr){
2 if(lastr - lastl <= ans)
3 return;
4 if(l > r){
5 if(l != r+1 && l != r+2 && (l - r - 2 > ans))
6 solve(QueryMin(r+1,l-1),QueryMax(r+1,l-1),r+1,l-1);
7 if(lastl != r && r - lastl > ans)
8 solve(QueryMin(lastl,r),QueryMax(lastl,r),lastl,r);
9 if(lastr != l && lastr - l > ans)
10 solve(QueryMin(l,lastr),QueryMax(l,lastr),l,lastr);
11 return;
12 }
13 else if(l == r){
14 return;
15 }
16 else{
17 ans = max(ans,r-l);
18 if(r != l+1 && r != l+2)
19 solve(QueryMin(l+1,r-1),QueryMax(l+1,r-1),l+1,r-1);
20 if(l != lastl && (l-lastl-1 > ans))
21 solve(QueryMin(lastl,l-1),QueryMax(lastl,l-1),lastl,l-1);
22 if(r != lastr && (lastr-r-1 > ans))
23 solve(QueryMin(r+1,lastr),QueryMax(r+1,lastr),r+1,lastr);
24 return;
25 }
26 }



转载于:https://www.cnblogs.com/bloodfish/archive/2012/03/08/2385675.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值