蓝桥模拟题 还款计算(二分搜索)

标题: 还款计算

银行贷款的等额本息还款方法是:
每月还固定的金额,在约定的期数内正好还完(最后一个月可能会有微小的零头出入)。

比如说小明在银行贷款1万元。贷款年化利率为5%,贷款期限为24个月。
则银行会在每个月进行结算:
结算方法是:计算本金在本月产生的利息: 本金 x (年利率/12)
则本月本金结余为:本金 + 利息 - 每月固定还款额
计算结果会四舍五入到“分”。

经计算,此种情况下,固定还款额应为:438.71

这样,第一月结算时的本金余额是:
9602.96
第二个月结算:
9204.26
第三个月结算:
8803.9
….
最后一个月如果仍按固定额还款,则最后仍有0.11元的本金余额,
但如果调整固定还款额为438.72, 则最后一个月会多还了银行0.14元。
银行会选择最后本金结算绝对值最小的情况来设定 每月的固定还款额度。
如果有两种情况最后本金绝对值相同,则选择还款较少的那个方案。

本题的任务是已知年化利率,还款期数,求每月的固定还款额度。

假设小明贷款为1万元,即:初始本金=1万元。
年化利率的单位是百分之多少。
期数的单位为多少个月。

输入为2行,
第一行为一个小数r,表示年率是百分之几.r<30
第二行为一个整数n,表示还款期限。 (6<=n<=120)

要求输出为一个整数,表示每月还款额(单位是:分)

例如:
输入:
4.01
24

程序应该输出:
43429

再比如:
输入:
6.85
36

程序应该输出:
30809

利用二分搜索的思想,先计算出每月还款的上下限,无利息时最少,最后一次还最多,即:
**int left = 1000000 / n;
int right = 1000000 * pow((100 + r)/ 100,n/12) / n;**
其中精确到分,我给虽有数字均扩大100,把问题转换成为整数的二分。
其中关键要对sum取double型因为分之后的小数位四舍五入时会对分位产生影响,
因此: sum = (double)(int)(sum + 0.5);手动四舍五入很关键。

#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector> 
#include<cmath>
#include<cstdio>
#include<functional>
#define INF 0x3f3f3f3f
using namespace std;

double r, n;
double ans[100];
double temp[100];
int cnt = 0;

int search(int x)
{
    double sum = 1000000;
    ///涉及精度,应该用double型
    for (int i = 0;i < n;i++)
    {   
        sum = sum + sum*r / 12 / 100 - x;
        ///此时应对sum四舍五入!
        sum = (double)(int)(sum + 0.5);
    }
    ans[cnt] = x;
    if (x == 30809) cout << sum << endl;
    if (x == 30808) cout << sum << endl;
    temp[cnt] = sum;
    cnt++;
    return sum;
}

int main()
{
    cin >> r >> n;
    int left = 1000000 / n;
    int right = 1000000 * pow((100 + r)/ 100,n/12) / n;
    int flag = 0;
    int mid;
    while (right>=left)
    {
        //mid = (right + left) / 2;
        mid = left + (right - left) / 2;
        int t=search(mid);
        if (t > 0) left = mid+1;
        else if (t < 0) right = mid;
        else {
            flag = 1;
            break;
        }
        if (left == right) break;
    }
    if (flag) cout << mid;
    else {
        double a = INF;
        int b = 0;
        for (int i = 0;i < cnt;i++)
        {
            if (abs(a) > abs(temp[i]))
            {
                a = temp[i];
                b = i;
            }
            else if (abs(a) == abs(temp[i]))
            {
                if (temp[i]>0 && a < 0)
                {
                    a = temp[i];
                    b = i;
                }
            }
        }
        printf("%.0f\n", ans[b]);
    }
    return 0;
}

也可以不记录所有的结余sum值,只需要比较,mid,mid-1,mid+1三个数的结果即可。如下所示:

#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector> 
#include<cmath>
#include<cstdio>
#include<functional>
#define INF 0x3f3f3f3f
using namespace std;
/*
有数据不对。。。。。
*/
double r, n;
int search(int x)
{
    double sum = 1000000;
    for (int i = 0;i < n;i++)
    {
        sum = sum + sum*r / 12 / 100 - x;
        sum = (int)(sum + 0.5);
    }
    return (int)sum;
}
struct node
{
    int x, mid;
};
node ans[5];
bool cmp(node s1, node s2)
{
    return abs(s1.x) < abs(s2.x);
}
int main()
{
    cin >> r >> n;
    int left = 1000000 / n;
    int right = 1000000 * pow((100 + r) / 100, n / 12) / n;
    int flag = 0;
    int mid;
    while (right >= left)
    {
        //mid = (right + left) / 2;
        mid = left + (right - left) / 2;
        int t = search(mid);
        if (t > 0) left = mid + 1;
        else if (t < 0) right = mid;
        else {
            flag = 1;
            break;
        }
        if (left == right) break;
    }
    ans[0].x = search(mid);ans[0].mid = mid;
    ans[1].x = search(mid+1);ans[1].mid = mid+1;
    ans[2].x = search(mid-1);ans[2].mid = mid-1;
    sort(ans, ans + 3, cmp);
    cout << ans[0].mid << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值