题目:http://poj.org/problem?id=1328
Description
Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.
We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.
Figure A Sample Input of Radar Installations
Input
The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.
The input is terminated by a line containing pair of zeros
Output
For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. "-1" installation means no solution for that case.
Sample Input
3 2
1 2
-3 1
2 1
1 2
0 2
0 0
Sample Output
Case 1: 2
Case 2: 1
基本思路:
首先,我想到因为把每个点投影到X轴上,于是我们知道每个点X轴Y轴的位置以及最长雷达距离,因为我们自然可以求得每个点能够被雷达X轴上某个区间的雷达探测。接着,我认为最优化的解决方案应该是利用聚类的算法来奖区间重合的点合并为一个雷达;我采用了层次聚类的方法,根据区间的重合度来作为点与点之间的相似度,从相似度高的点开始聚类,但是始终超时。优化时间的时候,我考虑到可以简化,无需考虑区间重合度,因此最简单的方法就是将所有点区间排序并增序地合并重叠的店。
代码:
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int sum,len;
struct daoyu
{
int x;
int y;
};
struct jiaodian
{
double llen;
double rlen;
};
int cmp(jiaodian a,jiaodian b)
{
return a.rlen>b.rlen;
}
int main()
{
int i,count,cases=1;
while(cin>>sum>>len&&sum!=0)
{
count=1;
daoyu *dao=new daoyu[sum];
jiaodian *jiao=new jiaodian[sum];
for(i=0;i<sum;i++)
cin>>dao[i].x>>dao[i].y;
if(len<0)
{
cout<<"Case "<<cases<<": "<<"-1"<<endl;
cases++;
}
else
{
for(i=0;i<sum;i++)
{
if(dao[i].y>len)
{
cout<<"Case "<<cases<<": "<<"-1"<<endl;
cases++;
break;
}
}
if(i==sum)
{
for(int j=0;j<sum;j++)
{
double temp=sqrt((double)(len*len-dao[j].y*dao[j].y));
jiao[j].llen=(double)(dao[j].x-temp);
jiao[j].rlen=(double)(dao[j].x+temp);
}
sort(jiao,jiao+sum,cmp);//按照x由大到小排列
double l=jiao[0].llen;
double r=jiao[0].rlen;
for(int k=1;k<sum;k++)
{
if(jiao[k].rlen>=l)
{
if(jiao[k].llen>l)
{
l=jiao[k].llen;
}
r=jiao[k].rlen;
}
else
{
l=jiao[k].llen;
r=jiao[k].rlen;
count++;
}
}
cout<<"Case "<<cases<<": "<<count<<endl;
cases++;
}
}
//scanf("\n");
}
return 0;
}
聚类算法的代码:(根据重合度来考虑合并点的优先级,但是时间开销比较大)
#include <iostream>
#include <math.h>
using namespace std;
double Max(double a, double b)
{
return a>b?a:b;
}
double Min(double a, double b)
{
return a<b?a:b;
}
int Matrix2Order(int x, int y, int len)
{
int a = x<y?x:y;
int b = x>y?x:y;
return a * len - a * (a + 1) / 2 + b - a - 1;
}
int MatrixLen(int len)
{
return Matrix2Order(len - 2, len - 1, len) + 1;
}
int main()
{
int run = 1;
while(true)
{
int num;
int dis;
cin>>num;
cin>>dis;
if(num == 0 && dis == 0)
{
break;
}
int (*island)[2] = new int[num][2];
for(int i = 0; i < num; i++)
{
cin>>island[i][0];
cin>>island[i][1];
}
double (*range)[2] = new double[num][2];
for(int i = 0; i < num; i++)
{
double tmp = sqrt(((double)(dis * dis - island[i][1] * island[i][1])));
range[i][0] = island[i][0] - tmp;
range[i][1] = island[i][0] + tmp;
}
int* availableN = new int[num];
int availableC = num;
for(int a = 0; a < num; a++)
{
availableN[a] = a;
}
float* availableM = new float[MatrixLen(num)];
int Count = num;
int j = 0;
int k;
for(; j < availableC-1; j++)
{
for(k = j + 1; k < availableC; k++)
{
double tmpL = Max(range[availableN[j]][0],range[availableN[k]][0]);
double tmpH = Min(range[availableN[j]][1],range[availableN[k]][1]);
if(tmpL <= tmpH)
{
availableM[Matrix2Order(availableN[j],availableN[k],num)] = (double)(Max(range[availableN[j]][1],range[availableN[k]][1] - Min(range[availableN[j]][0],range[availableN[k]][0])));
}
else
{
availableM[Matrix2Order(availableN[j],availableN[k],num)] = -1;
}
}
}
while(true)
{
double MinLikage = -1;
int MinX = -1;
int MinY = -1;
for(j = 0; j < availableC-1; j++)
{
for(k = j + 1; k < availableC; k++)
{
if(availableM[Matrix2Order(availableN[j],availableN[k],num)] != -1)
{
if(MinLikage == -1)
{
MinLikage = availableM[Matrix2Order(availableN[j],availableN[k],num)];
MinX = j;
MinY = k;
}
else if(MinLikage > availableM[Matrix2Order(availableN[j],availableN[k],num)])
{
MinLikage = availableM[Matrix2Order(availableN[j],availableN[k],num)];
MinX = j;
MinY = k;
}
}
}
}
if(MinX != -1 && MinY != -1)
{
Count -= 1;
int bigger = availableN[MinX]>availableN[MinY]?MinX:MinY;
int smaller = availableN[MinX]<availableN[MinY]?MinX:MinY;
if(bigger != availableC - 1)
{
availableN[bigger] = availableN[availableC - 1];
}
availableC -= 1;
range[availableN[smaller]][0] = Max(range[availableN[MinX]][0],range[availableN[MinY]][0]);
range[availableN[smaller]][1] = Min(range[availableN[MinX]][1],range[availableN[MinY]][1]);
for(int n = 0; n < availableC; n++)
{
if(n != smaller)
{
double tmpL = Max(range[availableN[n]][0],range[availableN[smaller]][0]);
double tmpH = Min(range[availableN[n]][1],range[availableN[smaller]][1]);
if(tmpL <= tmpH)
{
availableM[Matrix2Order(availableN[n],availableN[smaller],num)] = (double)(Max(range[availableN[n]][1],range[availableN[smaller]][1]) - Min(range[availableN[n]][0],range[availableN[smaller]][0]));
}
else
{
availableM[Matrix2Order(availableN[n],availableN[smaller],num)] = -1;
}
}
}
}
else
{
break;
}
}
std::cout<<"Case ";
std::cout<<run;
std::cout<<": ";
std::cout<<Count;
}
return 0;
}