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; }