CUMTOJ算法实验一

CUMTOJ算法实验一

问题 A: 判断字符串是否是手机号码

题目描述

手机号码是一串数字,长度为11位,并且第一位必须是1,现在给出一个字符串,我们需要判断这个字符串是否符合手机格式。

输入

多组测试数据。每组数据输入一个字符串。

输出

若该字符串符合手机号码格式,输出1,否则输出0。

样例输入

12345612345

样例输出

1

思路

可封装在一个返回 bool 的 Judge() 函数中,考虑三个方面:

  1. 是不是 11 位;
  2. 首位是不是为 “1”;
  3. 每位是不是数字。
代码
#include<iostream>
#include<string.h>
using namespace std;
const int num = 1000;
bool Judge(char str[]);
int main() {
    char str[num];
    while(cin >> str) {
        if(Judge(str))
			cout << "1" << endl;
        else
			cout << "0" << endl;
    }
    return 0;
}
bool Judge(char str[]) {
    if(strlen(str) != 11 || str[0] != '1') 
		return false;
    for(int i = 0; i < 11; i++) {
        if(str[i] < '0' || str[i] > '9')
            return false;
    }
    return true;
}

问题 B: 内部收益率

题目描述

手机号码是一串数字,长度为11位,并且第一位必须是1,现在给出一个字符串,我们需要判断这个字符串是否符合手机格式。

输入

多组测试数据。每组数据输入一个字符串。

输出

对于每组数据,输出仅一行,即项目的IRR,四舍五入保留小数点后两位。

样例输入

1
-1 2
2
-8 6 9
0

样例输出

1.00
0.50

思路

题目两边等式同乘 (1+IRR)T。则原题相当于求:CF0(1+IRR)T+CF1(1+IRR)T−1+⋯+CFT=0 的解,则可使用二分法。

L 初始值取 -1.0,R 初始值取常规正无穷大(我这里取100000)。

代码
#include <iostream>
#include <iomanip>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int inf_num = 100000;
const double eps = 1e-6;
int main() {
    int T;
    double cf[13] , l , r , m;
    while(cin >> T && T) {
        for(int i = 0; i <= T; i++)
            cin >> cf[i];
        l = -1.00;
        r = inf_num;
        while(r - l > eps) {
            m = (l + r) / 2;
            double sum = 0.0;
            for(int i = 0; i <= T; i++)
                sum += cf[i] * pow(1 + m , T - i);
            if(sum > 0)
				l = m;
            else
				r = m;
        }
        cout << setiosflags(ios::fixed) << setprecision(2);
        cout << l << endl;
    }
    return 0;
}

问题 C: 跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

输入

多组测试样例。每组测试样例包含一个整数n。(1<=n<=100)

输出

每组测试样例输出一行,表示青蛙跳上n级台阶的跳法数量.

所得到的结果模1000000007

样例输入

3
4

样例输出

3
5

思路

假设青蛙在第 n 级台阶,那么我们倒推一步,故易得青蛙跳台阶的问题就是斐波那契数列的问题
此题有时间限制,故用空间换时间,用一个数组存储结果
因为它每次可以跳 1 级台阶或者 2 级台阶,所以它上一步只能在第 n-1 级或者第 n-2 级台阶,每次都要对 1e9 + 7 取余所以可写出递推式:

Fib_seq[n] = (Fib_seq[n-1] + Fib_seq[n-2]) % mod;
代码
#include <iostream>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int arr_len = 101;
ll Fib_seq[arr_len] = {1 , 1};
int main() {
	int step_num;
	for(int i = 2; i < arr_len; i++)
        Fib_seq[i] = (Fib_seq[i - 1] + Fib_seq[i - 2]) % mod;
	while(cin >> step_num)
		cout << Fib_seq[step_num] << endl;
	return 0;
}

问题 D: 奶牛的聚会

题目描述

在这里插入图片描述

输入

在这里插入图片描述

输出

对于每组测试数据,输出 “Case #c: ans” ,其中c表示测试数据编号,ans表示消极情绪之和的最小值,结果四舍五入为一个整数。

样例输入

1
5
0.9 2
1.4 4
3.1 1
6.2 1
8.3 2

样例输出

Case #1: 300

思路
函数的凹凸性
  1. 设函数f(x)在区间[a,b]上连续,(a,b)内可导,
    如果在区间(a,b)上f(x)的一阶导数单调递增,那么f(x)在[a,b]上是凹的。
    如果在区间(a,b)上f(x)的一阶导数单调递减,那么f(x)在[a,b]上是凸的。
  2. 设函数f(x)在区间[a,b]上连续,(a,b)内二阶可导,
    如果在区间(a,b)上f(x)的二阶导数>0,那么f(x)在[a,b]上是凸函数(图像为凹的)
    如果在区间(a,b)上f(x)的二阶导数<0,那么f(x)在[a,b]上是凹函数(图像为凸的)
三分法
  1. 三分法主要用于求解一个函数在某个区间内的极大(极小)值点,类似于二分法做一个比较:
二分法三分法
作用求解一个函数的零点求解一个函数的极大(极小)值点
条件函数在这个区间是单调函数函数在这个区间是凸(凹)函数

对于一个凹函数y=f(x),我们要求它的极小值点。

首先确定它的极小值点所在的区间为[l,r]

计算出两个三分点:

mid=(l+r)/2

mid2=(mid+r)/2

(其实这两个点的位置是灵活的)

此时 l < mid <mid2 < r

计算出对应的函数值 f(mid)和f(mid2)。

当f(mid)<f(mid2)时,则极小值点一定不会在mid2和r之间。

反之f(mid)>f(mid2)时,极小值点一定该不会在l和mid之间。

因此,当f(mid)<f(mid2)时,极小值点在[l,mid2]内。此时令l=l,r=mid2继续计算。

当f(mid)>f(mid2)时,极小值点在[mid,r]内。此时令l=mid,r=r继续计算。

直到这个区间足够小,可以认为l=r时,l就是所求的极小值点。(可接受的误差内)

代码
#include <iostream>
#include <cmath>
typedef long long ll;
using namespace std;
double x[50005][2];
int n;
double cal(double xx) {
    double sum = 0;
    for(int i = 0; i < n; i++)
        sum += fabs(x[i][0] - xx) * fabs(x[i][0] - xx) * fabs(x[i][0] - xx) * x[i][1];
    return sum;
}
int main() {
    int t;
    cin >> t;
    for(int w = 1; w <= t; w++) {
        cin >> n;
        for(int i = 0; i < n; i++)
        cin >> x[i][0] >> x[i][1];
        double L = -1000000 , r = 1000000;
        while(L + 0.00001 < r) {
            double Lmid = L + (r - L) / 3;
            double rmid = r - (r - L) / 3;
            if(cal(Lmid) < cal(rmid))
				r = rmid;
            else
				L = Lmid;
        }
        cout << "Case #" << w << ": " << (ll)(cal(L) + 0.5) << endl;
    }
    return 0;
}

问题 E: 光合作用

题目描述

蒜头是个爱学习的孩子,他总喜欢在生活中做一些小实验,这次蒜头想研究一下光合作用。蒜头的实验材料有如下几样:神奇的种子,普通的纸箱和一些光源。一开始,蒜头将种子均匀的种在了箱子底部,你可以将其看成 X 轴,种子的位置为 X 轴上的点。然后蒜头用纸板将箱子盖住,并在纸板上安装了一些光源(具体见图,顶上的为光源,光源两边与顶部的夹角都为45度,黄色部分为光照,绿色的为植物。)。神奇的种子会在有光的情况下一直向上生长直到没光为止。现在蒜头想知道当实验结束时每颗种子的高度是多少?
在这里插入图片描述

输入

第一行输入一个整数 T,表示测试数据的组数。

每组数据的第一行是三个整数 n,m,h(1<=n,m<=1e5,0<=m<=1e5,1<=h<=1e4),n表示种子数(编号为1,2…n),m表示光源数,h 表示箱子的高度。

接下来m行,每行一个整数Xi表示第i个光源在顶部的位置。

输出

对于每组测试数据,请输出n行,每行一个数表示第i颗种子的最终高度。

样例输入

2
7 1 2
4
4 4 1
1
2
3
4

样例输出

0
0
1
2
1
0
0
1
1
1
1

思路

二分找到当前位置的前后。

代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int max_num = 1e5 + 5;
int arr[max_num];
int main() {
    int T;
    cin >> T;
    while(T--) {
        int n , m , h;
       cin >> n >> m >> h;
        for(int i = 1; i <= m; i++)
            cin >> arr[i];
        sort(arr + 1 , arr + m + 1);
        for(int i = 1; i <= n; i++) {
            int ans = 0;
            int cnt = lower_bound(arr + 1 , arr + m + 1 , i) - arr;
            if(cnt == 1 && m != 0)
                ans = max(ans , h - arr[cnt] + i);
            else if(cnt == m + 1 && m != 0)
                ans = max(ans , h - i + arr[cnt - 1]);
            else if(m != 0)
                ans = max(0 , max(h - i + arr[cnt - 1] , h - arr[cnt] + i));
            cout << ans << endl;
        }
    }
    return 0;
}

本文参考了如下大佬们的文章
https://comydream.github.io/2018/09/28/algorithm-experiment-1/
https://www.cnblogs.com/yfr2zaz/p/11083207.html
https://www.cnblogs.com/syiml/p/3675214.html
https://www.cnblogs.com/littlepear/p/6033783.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值