找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3544|回复: 1

2774:木材加工

[复制链接]
发表于 2011-12-8 10:21:36 | 显示全部楼层 |阅读模式
时间限制: 1000ms内存限制: 65536kB描述木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头,需要得到的小段的数目是给定了。当然,我们希望得到的小段越长越好,你的任务是计算能够得到的小段木头的最大长度。

木头长度的单位是厘米。原木的长度都是正整数,我们要求切割得到的小段木头的长度也要求是正整数。
输入
第一行是两个正整数NK(1 ≤ N ≤ 10000, 1 ≤ K ≤ 10000),N是原木的数目,K是需要得到的小段的数目。
接下来的N行,每行有一个1到10000之间的正整数,表示一根原木的长度。
 输出输出能够切割得到的小段的最大长度。如果连1厘米长的小段都切不出来,输出"0"。样例输入3 7232124456样例输出114
 楼主| 发表于 2011-12-8 10:22:12 | 显示全部楼层
链接: http://poj.grids.cn/practice/2774

这个
题可以用二分解,虽然也有dp的解法。可能用二分解这个题不是很明显,但是确实是可以的。最大的解就是所有的棍子长/要求的棍子数,最小的解是0,直接在其中进行二分即可。这个题属于二分出最大满足条件的解的情况。这个题为什么能够二分了。我是这样想的。首先,解空间确实是有序的吧,从数字0-数字nSum/nK。其次,对于任意一个处于这个范围内的数字,只有满足和满足题目要求2种情况,那么和我们二分数字有什么区别了,我们二分一个有序数组,看里面有没有某个数字,是不是也只要判断下nMid满足是否条件是吧。所以,这个题是可以二分的。二分的条件就是解空间有序的,或者可以方便在解空间里面跳跃。而且这个题的二分还需要点技巧,因为是查找满足条件的最大解。

代码:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #define MAX (10000 + 10)
  5. using namespace std;
  6. int nN, nK;
  7. int nWoods[MAX];
  8. bool IsAnsOk(int nAns)
  9. {
  10.     if (nAns == 0)
  11.     {
  12.         return true;
  13.     }
  14.     else
  15.     {
  16.         int nTotal = 0;
  17.         for (int i = nN - 1; i >= 0; --i)
  18.         {
  19.             nTotal += nWoods[i] / nAns;
  20.             if (nTotal >= nK)
  21.             {
  22.                 return true;
  23.             }
  24.         }
  25.         return false;
  26.     }
  27. }
  28. int SearchAns(int nMax)
  29. {
  30.     int nBeg = 0, nEnd = nMax;
  31.     while (nBeg <= nEnd)
  32.     {
  33.         int nMid = (nBeg + nEnd) / 2;
  34.         if (IsAnsOk(nMid))
  35.         {
  36.             nBeg = nMid + 1;
  37.         }
  38.         else
  39.         {
  40.             nEnd = nMid - 1;
  41.         }
  42.     }
  43.     return nBeg - 1;
  44. }
  45. int main()
  46. {
  47.     while (scanf("%d%d", &nN, &nK) == 2)
  48.     {
  49.         int nSum = 0;
  50.         for (int i = 0; i < nN; ++i)
  51.         {
  52.             scanf("%d", &nWoods[i]);
  53.             nSum += nWoods[i];
  54.         }
  55.         sort(nWoods, nWoods + nN);
  56.         int nMax = nSum / nK;
  57.         printf("%d\n", SearchAns(nMax));
  58.     }
  59.     return 0;
  60. }
复制代码
所以,只是把==换成了IsAnsOk函数调用而已...而且由于这是查找最大解,返回值做了下变化而已...
仔细分析二分的写法(我的另一篇文章(标题是关于密码的一个解题报告)有说明),
其实写出查找最大解和最小解的二分都不是件麻烦的事情...
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-28 02:06 , Processed in 0.011819 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表