POJ No.1769

分类:dp | 线段树

题意转化:用m个区间去覆盖1~n,求所需区间的最小数目。

分析:假设输入的n个数中第i个数是应该输出的最大值,则通过所选若干区间的操作后,若能将其从第i个位置移动到第n个,则Maximizer正常工作。由分析可知,如果i = 1时maxmizer可以正常工作,则对于任意地i都可以正常工作。所以,不妨假设输入的第一个数是应该输出的最大值,然后利用DP求解。

dp[i]:= 将最大值从位置1移动到位置i时所需的最小区间数。

初始化:

  dp[1] = 0(不需要移动时所需区间数为0)

  dp[i] = INF(i > 1)

状态更新:

   dp[ti] = min(dp[ti], dp[j] + 1)且si<=j <= ti

最坏时间复杂度:O(mn)

核心代码实现:

void solve(int n, int m)//n个数 m个区间

{

  fill(dp, dp + n + 1, INF);

  dp[1] = 0;

  for(int i = 0; i <= m; ++i)

  {

    for(int j = s[i];  j <= t[i]; ++j)

      dp[t[i]] = min(dp[t[i]], dp[j] + 1);

  }

  cout << dp[n] << endl;

}

本题可以利用线段树进行优化:查找区间(s[i], t[i])的最小值query(s[i], t[i])

优化后的代码实现:

void solve(int n, int m)

{//时间复杂度O(mlogn)

  fill(dp, dp + n + 1, INF);

  dp[1] = 0;

  build_sbt(n);//构造线段树

  update(1, 0);//将位置1置0

  for(int i = 0; i < m; ++i)

  {

    int v = min(dp[t[i]], query(s[i], t[i]));

    dp[t[i]] = v;

    update(t[i], v);

  }

  cout << dp[t[i]] << endl;

}

 

转载于:https://www.cnblogs.com/aizi/p/4662584.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值