问题描述求两个大的正整数相除的商输入数据第 1行是测试数据的组数 n,每组测试数据占 2行,第 1行是被除数,第 2行是除数。 |
每组测试数据之间有一个空行,每行数据不超过 100个字符输出要求 n行,每组测试数据有一行输出是相应的整数商输入样例 |
3 2405337312963373359009260457742057439230496493930355595797660791082739646 2987192585318701752584429931160870372907079248971095012509790550883793197894 |
10000000000000000000000000000000000000000 10000000000 |
5409656775097850895687056798068970934546546575676768678435435345 1 |
0 1000000000000000000000000000000 5409656775097850895687056798068970934546546575676768678435435345 |
基本的思想是反复做减法,看看从被除数里昀多能减去多少个除数,商就是多少。一个一个减显然太慢,如何减得更快一些呢?以 7546除以 23为例来看一下:开始商为 0。先减去 23的 100倍,就是 2300,发现够减 3次,余下 646。于是商的值就增加 300。然后用 646减去 230,发现够减 2次,余下 186,于是商的值增加 20。昀后用 186减去 23,够减 8次,因此昀终商就是 328。 |
所以本题的核心是要写一个大整数的减法函数,然后反复调用该函数进行减法操作。计算除数的 10倍、100倍的时候,不用做乘法,直接在除数后面补 0即可。 参考程序 #include <iostream> #include <string> #define MAX_LEN 200 char szLine1[MAX_LEN + 10]; char szLine2[MAX_LEN + 10]; int an1[MAX_LEN + 10]; //被除数, an1[0]对应于个位 int an2[MAX_LEN + 10]; //除数, an2[0]对应于个位 int aResult[MAX_LEN + 10]; //存放商, aResult[0]对应于个位 /* Substract函数:长度为 nLen1的大整数 p1减去长度为 nLen2的大整数 p2 减的结果放在 p1里,返回值代表结果的长度 如不够减返回-1,正好减完返回 0 p1[0]、p2[0]是个位 */ int Substract( int * p1, int * p2, int nLen1, int nLen2) { int i; if( nLen1 < nLen2 ) return -1; //下面判断 p1是否比 p2大,如果不是,返回-1 bool bLarger = false; if( nLen1 == nLen2 ) { for( i = nLen1-1; i >= 0; i -- ) { if( p1[i] > p2[i] ) bLarger = true; else if( p1[i] < p2[i] ) { if ( ! bLarger ) return -1; } } } for( i = 0; i < nLen1; i ++ ) { //做减法 p1[i] -= p2[i]; //要求调用本函数时给的参数能确保当 i>=nLen2时,p2[i] = 0 if( p1[i] < 0 ) { p1[i]+=10; p1[i+1] --; } } for( i = nLen1 -1 ; i >= 0 ; i-- ) if( p1[i] ) return i + 1; return 0; } int main() { int t, n; char szBlank[20]; scanf("%d", &n); for( t = 0; t < n; t ++ ) { scanf("%s", szLine1); scanf("%s", szLine2); int i, j; int nLen1 = strlen( szLine1); memset( an1, 0, sizeof(an1)); memset( an2, 0, sizeof(an2)); memset( aResult, 0, sizeof(aResult)); j=0; for( i = nLen1 - 1;i >= 0 ; i --) an1[j++] = szLine1[i] - '0'; int nLen2 = strlen(szLine2); j=0; for( i = nLen2 - 1;i >= 0 ; i --) an2[j++] = szLine2[i] - '0'; if( nLen1 < nLen2 ) { printf("0\n"); continue; } nLen1 = Substract( an1, an2, nLen1, nLen2) ; if( nLen1 < 0) { printf("0\n"); continue; } else if( nLen1 == 0) { printf("1\n"); continue; } aResult[0] ++; //减掉一次了,商加 1 //减去一次后的结果长度是 nLen1 int nTimes = nLen1 - nLen2; if( nTimes < 0) //减一次后就不能再减了 goto OutputResult; else if( nTimes > 0 ) { //将 an2 乘以 10的某次幂,使得结果长度和 an1相同 for( i = nLen1 -1; i >= 0; i -- ) { if( i >= nTimes ) an2[i] = an2[i-nTimes]; else an2[i] = 0; } } nLen2 = nLen1; for( j = 0 ; j <= nTimes; j ++ ) { int nTmp; //一直减到不够减为止 //先减去若干个 an2×(10 的 nTimes 次方), //不够减了,再减去若干个 an2×(10 的 nTimes-1 次方),...... while( (nTmp = Substract(an1, an2+j, nLen1, nLen2-j)) >= 0) { nLen1 = nTmp; aResult[nTimes-j]++; //每成功减一次,则将商的相应位加 1 } } OutputResult: //下面的循环统一处理进位问题 for( i = 0; i < MAX_LEN; i ++ ) { if( aResult[i] >= 10 ) { aResult[i+1] += aResult[i] / 10; aResult[i] %= 10; } } //下面输出结果 bool bStartOutput = false; for( i = MAX_LEN ; i >= 0; i -- ) if( bStartOutput) printf("%d", aResult[i]); else if( aResult[i] ) { printf("%d", aResult[i]); bStartOutput = true; } if(! bStartOutput ) printf("0\n"); printf("\n"); } system("pause"); return 0; } |
问题一、忘了针对每一组测试数据,都要先将 an1, an2和 aResult初始化成全 0,而是一共只初始化了一次。这导致从第二组测试数据开始就都不对了。 |
问题二、减法处理借位的时候,容易忽略连续借位的情况,比如 10000 – 87,借位会一直进行到 1。