二分查找是在一个单调序列中,通过不断缩小解可能存在的范围,从而求得最优解的方法。
它具有多种变化与应用,并不只在一个序列中查找一个数。
题目:
poj 1064:http://poj.org/problem?id=1064
题意:
有n根绳子,问能剪出k条长度相等的绳子的最大长度是多少。
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int M = 10000 + 20;
int n, k;
double len[M], maxx;
bool judge(double l)
{
int sum = 0;
for(int i = 0; i < n; i++)
sum += (int)(len[i] / l);
return sum >= k;
}
void bs()
{
double lb = 0, ub = maxx;
for(int i = 0; i < 100; i++)
{
double mid = (lb + ub) / 2.0;
if(judge(mid))
lb = mid;
else
ub = mid;
}
printf("%.2f\n", floor(ub * 100) / 100);
}
int main()
{
// freopen("input.txt", "r", stdin);
while(cin >> n >> k)
{
maxx = 0;
for(int i = 0; i < n; i++)
{
cin >> len[i];
maxx = max(maxx, len[i]);
}
bs();
}
}
poj 2456 : http://poj.org/problem?id=2456
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M = 100010;
int loc[M], n, m;
bool judge(int a)
{
int d = 0, c;
for(int i = 1;i < n; i++)
{
c = d + 1;
while(c < m && loc[c] - loc[d] < a)
c++;
if(c == m)
return false;
d = c;
}
return true;
}
void solve()
{
int lb = 0, ub = 999999;
while(ub - lb > 1)
{
int mid = (lb + ub) / 2;
if(judge(mid))
lb = mid;
else
ub = mid;
}
cout << lb << endl;
}
main()
{
// freopen("input.txt", "r", stdin);
while(cin >> m >> n)
{
for(int i = 0; i < m; i++)
scanf("%d", &loc[i]);
sort(loc, loc + m);
solve();
}
}
三分查找是在一个凹性或凸性函数中通过两两比较寻找最值,如下图。
题目:
hdoj 4355: http://acm.hdu.edu.cn/showproblem.php?pid=4355
AC代码:
#include<cstdio>
#include<cmath>
const int M = 5e4 + 20;
const double eps = 1e-4;
double x[M], w[M];
int T, n;
double sum(double a)
{
double ret = 0;
for(int i = 0; i < n; i++)
{
double p = fabs(x[i] - a);
ret += w[i] * p * p * p;
}
return ret;
}
double ts(double l, double r)
{
while(r - l > eps)
{
double lmid = (l * 2 + r) / 3, rmid = (l + r * 2) / 3;
double f1 = sum(lmid), f2 = sum(rmid);
if(f1 > f2)
l = lmid;
else
r = rmid;
}
return l;
}
main()
{
scanf("%d", &T);
for(int k = 1; k <= T; k++)
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%lf %lf", &x[i], &w[i]);
double f = ts(x[0], x[n - 1]);
printf("Case #%d: %.0lf\n", k, sum(f));
}
}