在某些看似涉及浮点计算的问题中,其实可以通过一些手段转化成整数计算问题,从而保证精度。
例如POJ3347
题意:依次给出n个正方形的边长,要求在第一象限内依次放入正方形,满足:①放入第i个正方形时,第i个正方形与前面的正方形都不重合;②放入正方形时,要求一个顶点在x轴上,且坐标值最小。求放完所有正方形后,从高处向下照射竖直平行光,未被完全遮挡的正方形的序号。
思路:本题在求解时用到的数据是每个正方形覆盖的区间,即与正方形的斜对角线长度相关。而给出的正方形边长是整数,则斜对角线为一个整数乘上sqrt(2)。本题卡了精度,能过的正确解法是,将所有正方形的边长延长sqrt(2)倍,从而使斜对角线变成整数,可以不失精度的处理问题。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;
typedef double db;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,s,t) for(int i=s;i>=t;i--)
#define ms0(ar) memset(ar,0,sizeof ar)
#define ms1(ar) memset(ar,-1,sizeof ar)
#define Ri(x) scanf("%d",&x)
#define Rii(x,y) scanf("%d%d",&x,&y)
int n,a[60],b[60];
int main(){
while(Ri(n),n){
rep(i,1,n){
Ri(a[i]);
b[i]=0;
rep(j,1,i-1)
b[i]=max(b[i],b[j]+2*min(a[i],a[j]));
}
rep(i,1,n){
int r=a[i]+b[i],l=b[i]-a[i];
rep(j,1,n){
if(j<i&&a[j]>a[i]) l=max(a[j]+b[j],l);
if(j>i&&a[j]>a[i]) r=min(b[j]-a[j],r);
}
if(l<r) printf("%d ",i);
}
printf("\n");
}
return 0;
}
例如UVALive3905
题意:给定一个矩形照相机的左下角(0,0)和右上角(w,h),n个流星的初始位置及速度向量,求同一时刻能照到的流星的最大值(在边界的流星不能被照到)。其中速度向量(a,b)满足|a|<=10,|b|<=10。
思路:首先解出某个流星在照相机范围内的时间区间,易得时间区间的端点是分母为a或者b的有理数。而该题的解题方法是对时间区间的端点进行离散化处理,只需要有大小关系即可。从而由a,b的范围可知,可以将所有区间端点乘上lcm(1,2,…,10)=2520即可转化为整数,并且不影响大小关系。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
#define rep(i,s,t) for(ll i=(s);i<=(t);i++)
#define per(i,s,t) for(ll i=(s);i>=(t);i--)
#define ms0(ar) memset(ar,0,sizeof ar)
#define ms1(ar) memset(ar,-1,sizeof ar)
#define Ri(x) scanf("%d",&x)
#define Rii(x,y) scanf("%d%d",&x,&y)
#define De(x,sy) cout<<'#'<<sy<<' '<<x<<'\n'
#define Db(x,y,sy) cout<<'#'<<sy<<' '<<x<<' '<<y<<'\n'
const int N=1e5+5,INF=0x3f3f3f3f,P=2520;
int t,w,h,n,l[N],r[N];
bool c[N<<1];
int main(){
Ri(t);
while(t--){
Rii(w,h);Ri(n);
int x,y,a,b,tot=0;
rep(i,1,n){
Rii(x,y);Rii(a,b);
int l1,l2,r1,r2;
if(a) l1=max(0,min(-x*P/a,(w-x)*P/a)),r1=max(0,max(-x*P/a,(w-x)*P/a));
else if(x>0&&x<w) l1=0,r1=INF;
else continue;
if(b) l2=max(0,min(-y*P/b,(h-y)*P/b)),r2=max(0,max(-y*P/b,(h-y)*P/b));
else if(y>0&&y<h) l2=0,r2=INF;
else continue;
int L=max(l1,l2),R=min(r1,r2);
if(L<R){
tot++;
l[tot]=L,r[tot]=R;
}
}
sort(l+1,l+tot+1);
sort(r+1,r+tot+1);
int sl=1,sr=1,cnt=0,ans=0,sum=0;
l[tot+1]=INF;
while(sl<=tot||sr<=tot)
if(l[sl]<r[sr]||sr>tot) c[++cnt]=0,sl++;
else c[++cnt]=1,sr++;
rep(i,1,cnt)
if(c[i]) sum--;
else sum++,ans=max(ans,sum);
printf("%d\n",ans);
}
return 0;
}
本文探讨如何将涉及浮点计算的问题转换为整数计算以保证精度,通过实例分析POJ3347和UVALive3905两道题目,介绍在正方形覆盖区间和流星轨迹计算中,通过延长边长和时间区间离散化的方法,将浮点数转化为整数,避免精度问题。
2万+

被折叠的 条评论
为什么被折叠?



