:题目例子:http://acm.zjgsu.edu.cn/JudgeOnline/showproblem?problem_id=1277
题目的大意是:
有N个房子在一条街上,(街是条直线)每个房子有个离这个街的最末端得距离。现在要在这条街上安装m个路由器 使得每个房子都能有个距离最近的路由器。并且使得所有房子和它距离最近的路由器之间的距离最大一个是最小的。
初一想就是 一个经典DP问题..
比如考虑 两个房子 一个路由器.肯定是将路由器放在中间位置..
于是对房子的距离排个序 就可以很快得出一个DP的表达式。
F[i,k]表示前i个房子放k个路由器的最优解..
则F[i,k]=min{max(F[j,k-1],(house[i]-house[j+1])/2),1<=j<i}
表示前j个房子放k-1路由器,第K个路由器放在第j+1和第i个房子的中点..
算法是O(m*n^2) 对于数据两n<=100000 无论如何都优化不了的DP 已经难以解决这个问题了..
后来经同实验室的朋友介绍了一个算法参数搜索的应用..
并找到一个论文.http://acm.zjgsu.edu.cn/Software/canshusousuo.doc(汪汀 著) 转载至中华信息网
关于怎么解这个问题就不多说了..就是找最优解.首先找一个最小的解,最大解,然后二分判断这个某个解是否是可行解。
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int house[100002];
int n,m;
bool isok(int value)
{
int i=1,j,p=1;
for(j=1;j<=n;j++)
{
if(i>m) return false;
if((house[j]-house[p])*10>value*2)
{
p=j;
i++;
}
}
if(i<=m)
return true;
return false;
}
void AC()
{
int ans;
int low=0,hight=(house[n]-house[0])*10,mid;
while(low<=hight)
{
mid=(low+hight)/2;
if(isok(mid))
hight=mid-1;
else
low=mid+1;
}
if(isok(low))
ans=low;
else
ans=hight;
printf("%.1lf\n",ans*1.0/10);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d",&house[i]);
house[0]=0;
sort(house,house+n+1);
AC();
}
}
posted on 2009-04-12 12:41
米游 阅读(1679)
评论(2) 编辑 收藏 引用 所属分类:
ACM