您的位置:首页 > 其它

nyoj 12 喷水装置(二)

2012-08-21 19:21 323 查看
http://acm.nyist.net/JudgeOnline/problem.php?pid=12

这道题是一道典型的贪心,可以转化为区间覆盖问题。

首先把圆的覆盖转化成线段,草坪转化为定长线段。即转化成直线上的线段覆盖问题,就是求用最少的线段数把整个区域都覆盖了,不能覆盖的输出0。

这道题做的有点慢,主要是细节没注意好。用了好几个测试数据才改正过来的。我的错主要是处在len的计算上了,没注意到len是不断变化的,是随着a[i],b[i]的变化而变化的!!!!!!必须现用现算!

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int x[10010],r[10010];
int main()
{
	int N;
	cin>>N;
	while(N--){
		int n,w,h;
		int num=0;
		cin>>n>>w>>h;
		memset(x,0,sizeof(x));
		memset(r,0,sizeof(r));
		for(int i=0;i<n;i++)
			cin>>x[i]>>r[i];
		//把已知量变成线段,典型的区间覆盖问题
	    double a[10010],b[10010],len[10010];
		double l=0;
	 	memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(len,0,sizeof(len));
		for(int i=0;i<n;i++){
			if(r[i]>h/2)
			l=sqrt(r[i]*r[i]-h/2*h/2);
			else l=0;
			a[i]=x[i]-l;
			b[i]=x[i]+l;
			if(a[i]<0) a[i]=0;
			if(b[i]>w) b[i]=w;//预处理,去掉多余的部分 
			len[i]=b[i]-a[i];
		}
		//for(int i=0;i<n;i++)
		//	cout<<"a["<<i<<"]="<<a[i]<<"  b["<<i<<"]="<<b[i]<<endl;
		
		//sort
		for(int i=0;i<n-1;i++)
			for(int j=i+1;j<n;j++){
				if(a[i]>a[j]) {
					swap(a[i],a[j]);
					swap(b[i],b[j]);
				}
			}
		
		double be=0,max; //begin and the max of length
		//for(int i=0;i<n;i++)
		//	cout<<"a["<<i<<"]="<<a[i]<<"  b["<<i<<"]="<<b[i]<<endl;
		for(int k=0;k<n;){			
			if(a[k]!=be) 
				break;		
			max=0;
			for(int i=k;i<n;i++){
				len[i]=b[i]-a[i];
				if(a[i]==be&&len[i]>max){
					max=len[i];
					k=i;
				}
			}
			//cout<<"the max k="<<k<<endl;
			be=be+max;
			num++;
			if(be>=w) {
				cout<<num<<endl;
				break;
			}
			//cout<<"num="<<num<<" "<<"be="<<be<<endl; 
			//再做处理,忽略所有区间在be之前的部分,新的起点是be 
			while(b[k]<=be&&k<n) k++;
			//cout<<"k="<<k<<endl;
			for(int m=k;m<n;m++)
				if(a[m]<=be&&b[m]>=be) 
					a[m]=be;
		}
		if(be<w)cout<<"0"<<endl;
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: