题目背景——这是我从现实生活中发现的问题,自己尝试编程解决
我每天都会使用不背单词APP背英语单词,这个APP有个签到系统,规则如下图所示:
上述签到奖励相当于一个里程碑系统,之前我有一天忘记签到,中断了我400+天的连续签到,今天是重新签到的第7天,我发现这个里程碑系统又重新激活了,我又获得了35酷币的额外奖励,那么问题就来了,只有n天的时间,如果我想要每天的收益最大,我应该一直连续签到呢?还是该达到某一个特定里程碑就停止签到,然后重新循环呢?
注意:
- 每日签到的固定收入是10酷币,如果达到相应天数(要求连续)才会有上面的里程碑奖励
- 重新开始里程碑的条件是有一天没有签到,即没有酷币收益
虽然我已经有了几万的酷币,还是不嫌多,当然这篇博文还是建议不背单词新用户查阅以最快白嫖终生大会员
分析
- 可以编写程序模拟这个签到系统,输入为当前连续签到的天数,输出为应得的酷币总数
- 计算从1到365天连续签到情况下,每日的平均酷币数目,平均酷币数最大的连续签到天数
代码
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
using namespace std;
int signin(int days) {//签到酷币总数计算,采用递归
if (days == 1) {
return 10;
}
switch (days) {
case 7:
return 45 + signin(--days);
case 30:
return 160 + signin(--days);
case 90:
return 460 + signin(--days);
case 180:
return 910 + signin(--days);
case 360:
return 1810 + signin(--days);
default:
return 10 + signin(--days);
}
}
struct strategy {
int days;
int sums;
float average;
};
bool cmp(strategy a, strategy b) {
if (a.average >= b.average ) {
return true;
} else {
return false;
}
}
int main() {
strategy str[2000];
int n;
scanf("%d", &n);
n++;
for (int i = 1; i < n; i++) {
str[i].days = i + 1;
str[i].sums = signin(i);
str[i].average = (float)(signin(i)) / (i + 1);
}
sort(&str[1], &str[n], cmp);
printf("排名\t总天数\t连签数\t总数\t日均\n");
for (int i = 1; i < n; i++) {
printf("%d\t%d\t%d\t%d\t%f\n", i
, str[i].days, str[i].days - 1, str[i].sums, str[i].average);
}
return 0;
}
代码输入输出介绍
- 输入:n,n表示你能够连续签到的最大天数
- 输出:根据日均酷币数降序排列的所有签到方案
结论
显然,如果连续签到数目超过360天,那么将没有里程碑收益,日均收益肯定是越来越少的。
因此,最佳的策略就是签满360天之后gap一天,然后重新开始360天的循环,这样的收益是最大的!
另外,可以拓展一下这个问题,比如说,限定n天,要找出一个酷币总数最大的方法,那么就演变成了背包问题,签到里程碑的选择和gap天数的选择就是物品,限定的天数就是背包大小。
考虑到现实场景,好像没有人会被限定天数吧,那么就先留个坑,稍后再填!!