您的位置:首页 > 其它

uva 10023

2016-01-18 15:43 141 查看
这种大数开方的算法很神奇,步骤很简单,但是自己没有理解它的核心原理。

下面是转载的blog:

数学题(我更觉得是恶心模拟)

题意很清楚,就是给一个高精度整数,求它的平方根,数据保证一定是整数解

这个东西要用高精度各种搞(看过别人的报告说有些不用高精度,没心机看下去,自己硬是写了一堆高精度),主要就是模拟手算的方法

手算的方法这里说得很清楚了(希望看得到图片吧)

开根方法

笔算开根法:

例1:求



①将37625从个位起,向左每两位分一节:3,76,25

②找一个最大的数,使它的平方不大于第一节的数字,本题中得1(1的平方为1,而2的平方为4,大于3,所以得1).把1写在竖式中3的上方。

③将刚才所得的1平方写在竖式中3的下方,并相减,然后将76移写在本行(如图)

④将前面所得的1乘20,再加一个数a,写在竖式的左方(如图),并同时把a写在竖式的上方对准6。而这个所谓的a,是需要试验的,使它与(20+a)的积最大且不超过276.本题中所得的a为9

⑤用9乘29,再用276减去,所得的差写在下方

⑥继续反复运用步骤④和⑤。如果后面的数字不足,则补两个0,继续运算。如果最后的余数是0,则该数的算术平方根是有理数;如果被开方数是小数,小数部分在分节的时候是从十分位起,向右每两位小数分一节

————————————————————————————————

最后可以看到这题的通过率很低的,主要是这个模拟很多细节(个人觉得大牛莫鄙视),自己写了很久不敢提交,最终WA了一次,然后过了

建议本人的代码还是不要看了,很乱,主要是学会这个手算开根的方法,具体的代码还是自己实现吧

本人还没学java,应该用java的大数来写会方便很多

#include <cstdio>
#include <cstring>
#define N 1100
int big
,ans
,re
;
int biglen,anslen,relen;

int fun3(int *tmp , int tmplen)
{
//tmp是反序而re是正序的
if(tmplen<relen)      return -1;  //tmp<re
else if(tmplen>relen) return 1;   //tmp>re
else
{
int i,j;  //i指向tmp,j指向re
for(i=tmplen,j=1; j<=relen; j++,i--)
if(tmp[i] < re[j])         return -1;  //tmp<re
else if(tmp[i] > re[j])    return 1;   //tmp>re
return 0;   //两者相等
}
}

void fun2(int *n1 ,int &n1len)
{
int i,j,a;
int tmp
,tmplen,c,s;
for(a=0; a<10; a++)
{
n1[1]=a;
for(i=1,c=0; i<=n1len; i++)
{  s=n1[i]*a+c;  tmp[i]=s%10;  c=s/10; }
if(c)
{ tmp[i]=c; tmplen=i;}
else        tmplen=i-1;

//printf("tmplen=%d  ",tmplen);
//for(int i=tmplen; i>=1; i--) printf("%d",tmp[i]); printf("\n");

c=fun3(tmp,tmplen);  //tmp和re比较大小
if(c==0 || c==1)          //tmp=re或tmp>re,可以跳出
{
if(c && a>0) ans[++anslen]=--a;
else  ans[++anslen]=a;
//得到最新一位

break;
}
}
if(a>=10) ans[++anslen]=a=9;
if(a)
{
//printf("a=%d\n",a);
memset(tmp,0,sizeof(tmp));
for(i=1,c=0,n1[1]=a; i<=n1len; i++)
{  s=n1[i]*a+c;  tmp[i]=s%10;  c=s/10;  }
if(c)
{ tmp[i]=c; tmplen=i;}
else        tmplen=i-1;

//printf("tmplen=%d  ",tmplen);
//for(int i=tmplen; i>=1; i--) printf("%d",tmp[i]); printf("\n");

for(i=relen , j=1; i>=1; i--,j++)
{
if( re[i] >= tmp[j]) re[i]-=tmp[j];
else
{ re[i-1]--; re[i]=re[i]+10-tmp[j]; }
}
//消除re的前导0
for(i=1; i<=relen; i++) if(re[i]) break;
for(j=1;i<=relen; j++,i++) re[j]=re[i];
relen=--j;
}
//printf("relen=%d  ",relen);
//for(i=1; i<=relen; i++) printf("%d",re[i]); printf("\n");
return ;
}

void fun1(int *n1 , int &n1len)
{
int i,j,c,s;
//ans是正序保存的,最后要反序保存在n1中
n1[1]=0; c=0;
for(j=anslen , i=2; j>=1; j--,i++)
{
s=ans[j]*2+c;
n1[i]=s%10;
c=s/10;
}
if(c)  { n1[i]=c; n1len=i; } //最后还有进位
else   n1len=i-1;

//printf("n1len=%d  ",n1len);
//for(i=n1len; i>=1; i--) printf("%d",n1[i]); printf("\n");
}

void solve()
{
int n1
,n1len;
//1.先将ans*20保存在n1中,涉及高精度乘法
//2.然后枚举a,使(n1+a)*a<re
//n1+a涉及高精度加法,不过是高精度+一个个位数
//(n1+a)*a涉及高精度乘法,不过是高精度*一个个位数
//另外(n1+a)*a要与re高精度比较大小

fun1(n1,n1len);   //计算ans*20,并保存在n1中
fun2(n1,n1len);   //枚举a,并计算(n1+a)*a,并与re比较大小,并保存最新一位
//printf("anslen=%d  ",anslen);
//for(int i=1; i<=anslen; i++) printf("%d",ans[i]); printf("\n");
return ;
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
char tmp
;
scanf("%s",tmp+1);
biglen=strlen(tmp+1);
for(int i=1; i<=biglen; i++)
big[i]=tmp[i]-'0';
/*******先处理得到第一位,并保存余数******/
memset(ans,0,sizeof(ans));
memset(re,0,sizeof(re));
int i,j,a,s,c;
if(biglen%2)  s=big[1] , c=1;            //奇数位
else          s=big[1]*10+big[2] , c=2;  //偶数位
for(a=0; a*a<=s && a<10; ) a++;
if(a>=10) ans[1]=a=9;
else      ans[1]=--a;
anslen=1;
s=s-a*a;
if(s<10) { re[1]=s; relen=1; }
else     { re[2]=s%10; re[1]=s/10; relen=2; }

//消除re的前导0
for(i=1; i<=relen; i++) if(re[i]) break;
for(j=1;i<=relen; j++,i++) re[j]=re[i];
relen=--j;

//printf("relen=%d  ",relen);
//for(i=1; i<=relen; i++) printf("%d",re[i]); printf("\n");
//printf("anslen=%d ",anslen);
//for(int i=1; i<=anslen; i++) printf("%d",ans[i]); printf("\n");
/*******先处理得到第一位,并保存余数******/

while(c+1<biglen)  //c每次跳两位
{
re[relen+1]=big[c+1];
re[relen+2]=big[c+2];
relen+=2;

//消除re的前导0
for(i=1; i<=relen; i++) if(re[i]) break;
for(j=1;i<=relen; j++,i++) re[j]=re[i];
relen=--j;

//printf("relen=%d  ",relen);
//for(i=1; i<=relen; i++) printf("%d",re[i]); printf("\n");
solve();
c+=2;
}

for(int i=1; i<=anslen; i++) printf("%d",ans[i]); printf("\n");
if(T) printf("\n");
}
return 0;
}


转载自:http://www.cnblogs.com/scau20110726/archive/2013/02/02/2890453.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: