[bo][un]StarWing83[/un] 在 2008-10-3 11:52 的发言:[/bo]
那篇文章我找不到了……麻烦给个链接?
哦哈哈,经过我的反复查找,居然找到了这篇传说中的神秘帖子。。。
算法技巧小集合(C语言描述)
1.例题ct3_1: 个人所得税计算★
(源自 [url=http://]http://[/url] )
题目描述:
个人所得税计算方法:假设起征点为k元,
超过k到k+500这部分税率为0.05
超过k+500到k+2000这部分税率为0.1
超过k+2000到k+5000这部分税率为0.15
超过k+5000到k+20000这部分税率为0.2
超过k+20000到k+40000这部分税率为0.25
超过k+40000到k+60000这部分税率为0.3
超过k+60000到k+80000这部分税率为0.35
超过k+80000到k+100000这部分税率为0.4
超过k+100000的部分的税率为0.45
输入:
多组测试数据,每组一行,一行有两个整数n和k
n是收入,0<= k,n <= 2e9
当输入0 0的时候结束
输出:
输出要交的税的数额,保留2位小数
样例输入:
800 800
1000 800
2000 1000
0 0
样例输出:
0.00
10.00
75.00
题目看似很复杂,因为数据分段明显不少,并且看似没有关联。
从原题目的链接帖子的第一页里,你可以看到很多人写了N多if嵌套,
程序逻辑显得极其混乱,并且非常容易出错,
只要看他们提交的结果都不对就知道了。
如果是你,你会怎么写这一题的解答代码呢?
不妨在看后面解答之前先细心想想,等你想尽办法以后,
再看看以下的解答,也许那种恍然大悟的感觉会非常好哦!
以下先帖一段经典if嵌套的方法并且能通过的C代码:
程序代码:
#include <stdio.h>
int main(void)
{
int k,n;
while (scanf("%d%d",&n,&k),!(n==0&&k==0))//数据输入
{
double tax = 0.0;
if( n-k <= 0 ); //使用分段函数方式计算
else if ( n-k-500 < 0 )
tax = (n-k)*0.05;
else if( n-k-2000 < 0 )
tax = 500*0.05 + (n-k-500)*0.1;
else if ( n-k-5000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (-2000+n-k)*0.15;
else if ( n-k-20000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(n-k-5000)*0.2;
else if ( n-k-40000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(20000-5000)*0.2 +(k-n-20000)*0.25;
else if ( n-k-60000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(20000-5000)*0.2+(40000-20000)*0.25+(n-k-40000)*0.3;
else if ( n-k-80000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(20000-5000)*0.2+(40000-20000)*0.25+(60000-40000)*0.3
+(n-k-60000)*0.35;
else if ( n-k-100000 < 0)
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(20000-5000)*0.2+(40000-20000)*0.25+(60000-40000)*0.3
+(80000-60000)*0.35+(n-k-80000)*0.4;
else
tax = 500*0.05 + (2000-500)*0.1 + (5000-2000)*0.15
+(20000-5000)*0.2+(40000-20000)*0.25+(60000-40000)*0.3
+(80000-60000)*0.35+(100000-80000)*0.4+(n-k-100000)*0.45;
printf("%.2lf\n",tax); //输出计算结果
}
return 0;
}
首先要声明,帖此代码并不是给大家取笑,而事实上,面对这个题目,
很多初学者的确就是使用类似以上代码的变形(帖子里还有比这个更长的),
但偶认为他(她)们也的确思考过,只是实在觉得没有办法化简了。
偶也曾经见过有人写一个解24点游戏的程序,24点游戏就是给你四个数,
通过加入四则运算符和括号,使得表达式的值为24。
这个解24点游戏的程序需要全排列和运算符和括号穷举,对于初学者的确不容易。
那个人也挺“聪明”的,他知道四个数的排列不过24种,
三个符号的排列不过4^3=64种,括号不过5种,最多也不过24*64*5=7680种,
当中一些重复的,去掉后大约二三千种,于是他一种写一个if,
最后代码写了六七千行,也的确顺利地解决了。
这种方法也不失为一种算法,或者可以称为源代码级别穷举算法吧。
偶看到那个程序的代码的时候,不得不Orz程序作者的毅力。
但是,我们为什么要学算法?这个题目就回答了这个问题的一个方面:
好的算法可以让你的代码更清晰明了,更简短优美,
还有在代码有问题的时候也能够更容易发现错误的地方。
现在不讲那个24点,转回这个题目。你现在想到好办法了没有?
我们来简单一点,先考虑收n<=5000元,k=0的情况,有如下信息:
超过k到k+500这部分税率为0.05
超过k+500到k+2000这部分税率为0.1
超过k+2000到k+5000这部分税率为0.15
其实我们完全可以不要按照字面的逻辑来进行程序的分界,
我们可以把它们打乱。比如,
k+500到k+2000这部分,相当于征收两次税,且均为0.05
k+2000到k+5000这部分,相当于征收三次税,且均为0.05
那么原题目等价地换为:
超过k这部分需征收一次,税率为0.05
超过k+500这部分需再次征收,税率为0.05
超过k+2000这部分需再次征收,税率为0.05
结果全部均变为0.05,很合理地,我们想到循环,重复地做同一个东西。
于是,你现在再想想,还需要不需要写那么多的if语句呢?
并且if写得越多、写得越复杂就算容易错。我们需要一段简短漂亮的代码。
相信说到这里,您也差不多甚至已经想到解决办法了。
如果你已经想到了,那恭喜你!!!
以下为标准解答程序(下文简称“标程”),请细心阅读:
程序代码:
// http:// <stdio.h>
int main()
{
int n,k,t;
unsigned nBase[]={0,500,2000,5000,20000,
40000,60000,80000,100000,-1};
while(scanf("%d%d", &n, &k), n>0||k>0) //数据输入
{
double sum = 0;
for(n-=k,t=0; (unsigned)n>nBase[t]; ++t)
{
sum += n - nBase[t];
}
printf("%.2lf\n", sum/20.0); //输出计算结果
}
return 0;
}
而事实上,你可能会问,是不是那个税率等间距递增才能使用这种方法。
那偶告诉你,其实不等间距递增也没有问题的,甚至递增和递减混合也行,
一样可以使用此办法化简得如上仅10行左右代码,并且可扩展性可以很好。
这个就留给读者您自己思考一下吧。
// ************************************************************ //
// 本文源自飞燕之家在线测评论坛http://,转载清注明出处 //
// ************************************************************ //