码迷,mamicode.com
首页 > 其他好文 > 详细

POJ No.1769

时间:2015-07-20 21:18:52      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:

分类: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;

}

 

POJ No.1769

标签:

原文地址:http://www.cnblogs.com/aizi/p/4662584.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!