[关闭]
@LinKArftc 2015-08-14T11:51:31.000000Z 字数 3584 阅读 1138

二分

二分


upper_bound & lower_bound

"algorithm"里面提供了二分查找的函数 upper_bound 和 lower_bound。之前研究过,这里只简单说明下。

lower_bound 接受一个键值类型的参数。如果容器中某个元素的键值等于该参数,那么函数就返回指向该元素的迭代器。如果不存在这样的元素,则返回一个迭代器,指向第一个键值比参数大的元素。如果所有的元素的键值都比参数小,那么函数就返回容器的尾部,即等于end。

upper_bound 正好与 lower_bound相反。该函数返回的也是一个迭代器,指向第一个键值比参数大的元素,或者键值等于参数的元素。upper_bound返回的迭代器,指向键值大于参数的元素。如果所有元素的键值都比参数大,那么函数就返回容器尾部,即等于end。

基本模型

poj 1064

题意:给定 n 条绳子的长度,切割成 k 条长度相同的绳子,求这 k 条绳子每条最长能有多长?
PS:这题数据有问题

  1. /*
  2. ID: LinKArftc
  3. PROG: 1064.cpp
  4. LANG: C++
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <cstring>
  9. #include <algorithm>
  10. #include <cmath>
  11. using namespace std;
  12. double cable[10010];
  13. int main() {
  14. // freopen("input.txt", "r", stdin);
  15. int n, k;
  16. while (~scanf("%d %d", &n, &k)) {
  17. for (int i = 1; i <= n; i ++) scanf("%lf", &cable[i]);
  18. double l = 0.0, r = 100010.0, mid;
  19. for (int j = 0; j < 100; j ++) { //循环结束条件,根据精度选择循环次数
  20. mid = (l + r) / 2.0;
  21. int cur = 0;
  22. for (int i = 1; i <= n; i ++) cur += (int)(cable[i] / mid);
  23. if (cur >= k) l = mid;
  24. else r = mid;
  25. }
  26. printf("%.2f\n", double(int(l * 100)) / 100);
  27. }
  28. return 0;
  29. }

poj 3122

  1. /*
  2. ID: LinKArftc
  3. PROG: 3122.cpp
  4. LANG: C++
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <cstring>
  9. #include <algorithm>
  10. #include <cmath>
  11. using namespace std;
  12. const double pi = acos(-1.0);
  13. const int maxn = 10010;
  14. const double eps = 1e-8;
  15. double cake[maxn];
  16. int main() {
  17. // freopen("input.txt", "r", stdin);
  18. int T;
  19. scanf("%d", &T);
  20. while (T --) {
  21. int n, f;
  22. scanf("%d %d", &n, &f);
  23. for (int i = 1; i <= n; i ++) scanf("%lf", &cake[i]);
  24. double l = 0.0, r = 10010.0, mid;
  25. while (r - l > eps) { //double型二分的另一种结束条件
  26. mid = (l + r) / 2.0;
  27. int cnt = 0.0;
  28. for (int i = 1; i <= n; i ++) cnt += (int)((pi * cake[i] * cake[i]) / (pi * mid * mid));
  29. if (cnt >= f + 1) l = mid;
  30. else r = mid;
  31. }
  32. printf("%.4f\n", pi * l * l);
  33. }
  34. return 0;
  35. }

最大化最小值 & 最小化最大值

poj 2456

题意:给定 n 个牛舍的位置,使得 m 条牛的相邻两条牛之间的距离最小值最大化。

  1. /*
  2. ID: LinKArftc
  3. PROG: 2456.cpp
  4. LANG: C++
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <cstring>
  9. #include <algorithm>
  10. using namespace std;
  11. const int max_n = 100010;
  12. int n, m;
  13. int x[max_n];
  14. int main() {
  15. // freopen("input.txt", "r", stdin);
  16. while (~scanf("%d %d", &n, &m)) {
  17. for (int i = 1; i <= n; i ++) scanf("%d", &x[i]);
  18. sort(x + 1, x + n + 1);
  19. int l = 1, r = 1000000010, mid;
  20. while (r - l > 1) { //l, r都是整型,所以用这种方式跳出循环
  21. mid = (l + r) >> 1;
  22. int cnt = 1;
  23. int last = x[1];
  24. for (int i = 2; i <= n; i ++) {
  25. if (x[i] - last >= mid) {
  26. cnt ++;
  27. last = x[i];
  28. }
  29. }
  30. if (cnt >= m) l = mid; //注意区间,左闭右开
  31. else r = mid;
  32. }
  33. printf("%d\n", l); //区间左值有效
  34. }
  35. return 0;
  36. }

最大化平均值

poj 2976

题意:n 场考试中分别答对 a[i] 题,总题数分别为 b[i],允许去掉 k 场考试,求能达到的最高准确率。
思路:这题不能直接按照 a[i] / b[i] 贪心做,二分答案 x, 使得 ∑a[i] / ∑b[i] >= x,所以 ∑a[i] / ∑b[i] - x >= 0, 即 ∑(a[i] - x*b[i]) >= 0, 所以对 a[i] - x * b[i] 从大到小排序,贪心选择前 n - k 个

  1. /*
  2. ID: LinKArftc
  3. PROG: 2976.cpp
  4. LANG: C++
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <cstring>
  9. #include <algorithm>
  10. using namespace std;
  11. const int maxn = 1010;
  12. double a[maxn], b[maxn], c[maxn];
  13. bool cmp(double a, double b) {
  14. return a > b;
  15. }
  16. int main() {
  17. // freopen("input.txt", "r", stdin);
  18. int n, k;
  19. while (~scanf("%d %d", &n, &k)) {
  20. if (n == 0 && k == 0) break;
  21. for (int i = 1; i <= n; i ++) scanf("%lf", &a[i]);
  22. for (int i = 1; i <= n; i ++) scanf("%lf", &b[i]);
  23. int tot = n - k;
  24. double l = 0.0, r = 1.0, mid;
  25. for (int i = 0; i < 100; i ++) {
  26. mid = (l + r) / 2;
  27. for (int j = 1; j <= n; j ++) c[j] = a[j] - mid * b[j];
  28. sort(c + 1, c + n + 1, cmp);
  29. double sum = 0.0;
  30. for (int j = 1; j <= tot; j ++) sum += c[j];
  31. if (sum >= 0.0) l = mid;
  32. else r = mid;
  33. }
  34. printf("%.0f\n", l * 100);
  35. }
  36. return 0;
  37. }

poj 3111

与上一题类似

  1. /*
  2. ID: LinKArftc
  3. PROG: 3111.cpp
  4. LANG: C++
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. #include <cstring>
  9. #include <algorithm>
  10. #include <cmath>
  11. using namespace std;
  12. const int maxn = 100010;
  13. const double eps = 1e-8;
  14. struct Node {
  15. int id;
  16. double v, w, c;
  17. } jew[maxn];
  18. bool cmp(Node a, Node b) {
  19. return a.c > b.c;
  20. }
  21. int main() {
  22. // freopen("input.txt", "r", stdin);
  23. int n, k;
  24. while (~scanf("%d %d", &n, &k)) {
  25. double l = 0.0, r = 0.0, mid;
  26. for (int i = 1; i <= n; i ++) {
  27. scanf("%lf %lf", &jew[i].v, &jew[i].w);
  28. jew[i].id = i;
  29. r += jew[i].v;
  30. }
  31. while (fabs(l - r) > eps) {
  32. mid = (l + r) / 2.0;
  33. for (int i = 1; i <= n; i ++) jew[i].c = jew[i].v - mid * jew[i].w;
  34. sort(jew + 1, jew + n + 1, cmp);
  35. double sum = 0.0;
  36. for (int i = 1; i <= k; i ++) sum += jew[i].c;
  37. if (sum >= 0.0) l = mid;
  38. else r = mid;
  39. }
  40. printf("%d", jew[1].id);
  41. for (int i = 2; i <= k; i ++) printf(" %d", jew[i].id);
  42. printf("\n");
  43. }
  44. return 0;
  45. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注