ACM XYNUOJ 2153: 数字分隔(二)

                                          2153: 数字分隔(二)

                                                              时间限制: 1 Sec  内存限制: 64 MB

题目描述

在一个遥远的国家,银行为了更快更好的处理用户的订单,决定将一整串的数字按照一定的规则分隔开来,分隔规则如下:

1、实数的整数部分按照每三个数字用逗号分隔开(整数部分的高位有多余的0时,需先将多余的0过滤后,再进行数字分隔,如:0001234567 输出结果为1,234,567.00)

2、小数部分保留两位小数(四舍五入)

3、如果该数是负的,则在输出时需用括号将分隔后的数字括起来,例如:-10005.1645的输出结果为(10,005.16)  

输入

多组测试数据(以eof结尾),每行输入一个实数n(n的位数小于100)

输出

输出分隔后的结果

样例输入

0001234567
0.0000
-10005.1645

样例输出

1,234,567.00
0.00
(10,005.16)

思路:

  1. 将整数和小数分开
  2. 然后再对小数和整数部分进行处理
  3. 综合考虑多种情况,是否为负是否进位等

本题有很多方法可以实现,以下为个人方案。

难点:

  • 如何去除输入的多余的‘0’。
  • 对于输入的负数,它所带的‘-’怎么消除它可能带来的影响并将它最终转换为最后的'(' ')' 。
  • 采用什么方式实现四舍五入。
  • 有特殊情况如何处理(如输入值为-0,1234.,.1234,99.999)。
  • 如何准确输出逗号。

以下为未AC代码(个人代码):


#include <stdio.h>  
#include <string.h> 
int main()
{
	int i,j,len,cnt,n,f;
	char str[100];                               //存储输入的整数; 
	char *t;
	while(~scanf("%s",str)){                     //循环输入值
		            //由于以下方法存在读入.2345与2345.与-0与99.999这类特殊情况,故需要给数组赋初值 
	    char out[134]={'0'},temp[100]={'.','0','0','0'},home[100]={'0'},bad[100]={'1'};  //bad[]数组在99.99的特殊四舍五入情况下使用 
		            //out[134]为了在输入数达到99位时能有空间保存',' 给 str[0]初始值'0',以及temp初始值'.''0''0''0' 
		if(str[0]=='-') f=0;                                 //判断函数正负以在判断是否输出'('')' 
		else f=1;                                        //负数为0,正数为1 
		t=strchr(str,'.');                       //查找输入的小数点位置,若无返回NULL 
		//整数部分:利用home数组保存 
		            //如-00123则读取123,再如123则会读取123,而0.48则会跳过而保持初值0 
		if(str[0]=='0'||str[0]=='-'){			             //判断输入值是否带'0''-',是则利用正则运算跳过读取此类符合并读取小数点之前部分 
			if(str[0]=='.'||str[1]=='.') goto mark;          //依据上个if的判定条件和str[2]即为'.',则输入值为'0.**'和'.**'即0.48和.2345类的特殊情况
			sscanf(str,"%*[^1-9]%[^.]",home);             //若不是特殊情况则  
		}else sscanf(str,"%[^.]",home);          //不是的话则直接读取小数点前的数; 
		len=strlen(home);                        //计算整数部分长度 
		mark:                                    //mark标识,跳转至此以跳过输入值进整数部分home,采用初始值0  
		//小数部分 :利用temp数组保存带'.'的小数部分 
		if(t){                                   //利用能否查找成功判断是否含有小数部分   
			if(str[0]=='.') sscanf(str,"%[^\n]",temp);  //若为特殊情况即.2345全为小数部分则直接读取
			else if(str[strlen(str)-1]=='.') goto skip; //解决2345.的特殊情况,防止只读取一个'.' 
			else sscanf(str,"%*[^.]%[^\n]",temp);       //否,则跳过小数点前的整数部分再读取 
			if(temp[3]>'4'){                     //四舍五入开始                          
				temp[2]++;
				if(temp[2]>'9'){
					temp[1]++;                       
					temp[2]='0';                 //若进位则置'0' 
					if(temp[1]>'9'){
						home[len-1]++;  //若进位为整数,则整数部分即home数组末值++; 
						temp[1]='0';             //继续置0 
						for(i=len-2;i>=0;i--){   //避免99.999 整数部分循环检测是否四舍五入 
							if(home[i+1]>'9'){
								home[i]++;
								home[i+1]='0';
							}
						}
						if(home[0]>'9'){
							home[0]='0';
							strcat(bad,home);
							sscanf(bad,"%s",home);
							len++;
						}
					}
				}					
			}
		}
		skip:                                    //标识:解决2345.的特殊情况,保留小数部分初始值'.''0''0'0' 
		//整数部分添加','以存入新数组out[134]; 
		for(i=0,j=0,cnt=strlen(home)%3;i<strlen(home);i++,j++){
			//cnt为第一轮所需循环次数(每三个数输入一次',') 如1234,则cnt=1,结果为1,234 || 而12345则cnt=2结果为12,345 
			if(cnt--) out[j]=home[i];            //cnt若不为0,则直接将值转入out数组 
			else{                                //若整数位数为3的倍数,则第一次会输出输入结束
				if(j>0) out[j]=',';              //从第二位起,开始输入','  
				else j--;                        //避免整数位数为3的倍数时,第一次cnt=0直接输出','如123456输出 ,123,456
				cnt=3;                           //重置cnt 
				i--;                             //每输入一个','将i-1以避免遗漏 
			}
		}
		sscanf(temp,"%3s",temp);                 //此时temp已经完成四舍五入,将temp取前三位字符输入temp,即.987654变为.98 
		if(f) printf("%s\n",strcat(out,temp));   //如果f==1为正数则直接合并out和temp数组输出 
		else printf("(%s)\n",strcat(out,temp));  //如果f为负数则合并并带'('')'输出 
		memset(str,'\0',sizeof(str));            //由于要循环输入,每次循环结束初始化数组str; 
	} 
	return 0;
}

以下为AC代码:

#include<cstring>
#include<cstdio>
 
char s[200],str[200],ch[200]; //s 为原数  str整数 	ch小数
int temp;
char sc[1000];
  
void chaifei()   // 将整数存入 str   小数存入 ch 
{
	memset(str,'\0',sizeof(str));  //整数 
	memset(ch,'\0',sizeof(ch));  //小数 
	int len,i,j;
	len=strlen(s);
	for(i=0;i<len;++i)    //判断是否为负,去除前导 0 
	{
		if(s[i]=='-'){
			temp=0; 	continue;
		}	
		if(s[i]!='0')
			break;
	}
	if(s[i]=='.')    // 前导 0 去掉后 第一位为 '0' ,时 ,整数为 '0' 
	{
		str[0]='0',j=0;
		for(i+=1;i<len;++i){
			ch[j++]=s[i];
		} 
		for(;j<5;++j)    //小数位数不够 5 (大于 3 就ok) 补 '0',为后面计算方便 
			ch[j]='0';
	} 
	else if(i==len)     // 若 只输入 '0' 
	{
		str[0]='0';
		for(j=0;j<5;++j)
			ch[j]='0';
	} 
	else  //整数有值 
	{
		for(j=0;i<len;++i)
		{
			if(s[i]=='.')  // 整数存放结束 
				break;
			str[j++]=s[i];
		}
		if(i==len)   //如果没有小数时 
		{
			for(j=0;j<5;++j)
				ch[j]='0';
		} 
		else     //有小数时 
		{
			for(i+=1,j=0;i<len;++i){
				ch[j++]=s[i];
			}
			for(;j<5;++j)
				ch[j]='0';
		}
	}
}
int  xiaoshu()  //将小数倒着存入  sc 中 
{
	int k=0,q=0;
	if(ch[2]>'4')  // 判断 四舍五入 
		q=1;
	ch[1]+=q;
	q=0;
	if(ch[1]>'9') //是否进位 
	{
		q=1;
		ch[1]-=10;
	}
	sc[k++]=ch[1];
	ch[0]+=q;
	q=0;
	if(ch[0]>'9')   //是否进位 
	{
		q=1;
		ch[0]-=10;
	}
	sc[k++]=ch[0];
	sc[k++]='.';
	return q; // 进位  1  或  0 
}
 
int zhengshu(int q,int k)
{
	int len,i,j,flag=0;
	len=strlen(str);
	for(i=len-1;i>=0;--i)  //同样倒着存入 sc 
	{
		str[i]+=q;	q=0;
		if(str[i]>'9')  // 判断是否进位 
		{
			str[i]-=10;
			q=1;
		}
		if(flag!=0&&flag%3==0)  //判断是否加 ',' 
			sc[k++]=',';
		flag++;
		sc[k++]=str[i];
	}
	if(q==1)  // 若数为 9.99999时, 整数要向前进位时多了一个 '1'; 
	{
		if(flag!=0&&flag%3==0)   //判断是否加 ',' 
			sc[k++]=',';
		sc[k++]='1';
	}
	return k;
}
 
int main()
{
	int k;
	while(scanf("%s",s)!=EOF)
	{
		temp=1;  //  1 没有 '-' 号  0 有 '-' 号 
		chaifei();  //调用,将整数和小数分开 
		int q=xiaoshu(); //q 小数向整数 进位  0 或 1
		k=zhengshu(q,3); // 整数部分 ,k 为 sc 的长度 
		if(temp==0)  // 负号处理 
			printf("(");
		for(int i=k-1;i>=0;--i)  //倒着输出 
			printf("%c",sc[i]);
		if(temp==0)
			printf(")");
		printf("\n");	
	}
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/qq_30007603/article/details/81185914