题目链接:
说明:
DFS做法:
因为是填空题,不用考虑超时,首先先考虑暴力做法DFS来做,根据题意,30道题,有一个答题的先后顺序,上一道题答了之后才能答下道题,所以自然地需要一个参数来表示答到第几道题了,也就是递归的层数。同时因为目标是找获得70分的方案,所以需要一个参数来记录得到的分数。对于一道题:要么答对,分数+10;要么答错,分数清0。这就是dfs的两个分支。因此,一个dfs程序的框架就出来了,时间复杂度为O() 。
这道题有点难的地方是要仔细读清楚题目,不要漏掉:答错了就变成0分;答到100分就停止答题;在答任意题目的时候都可以放弃作答,就是说找到一个70分的方案也不返回。
让人意外的是,加上一些剪枝的判断,DFS这个解法提交到网站上没有超时。
详细的看代码(DFS):
//#include<iostream>
//#include<queue>
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e3+30;
int ans = 0;
//这道题有点难的地方是要仔细读清楚题目,
//不要漏掉:答错了就变成0分;答到100分就停止答题;在答任意题目的时候都可以放弃作答
void dfs(int k,int score)//第几道题,得的分数
{
//答道100分,停止
if(score==100) return;
//答满30道题 停止
if(k>31) return;
//两种绝对不可能有70分 的情况
if(score>=80&&k>=25) return;
if(score==0&&k>=25) return;
//达到70分记录,但不返回,可能继续作答
if(score==70){
ans++;
}
if(score+10<=100)
dfs(k+1,score+10);
dfs(k+1,0);
}
signed main() {
cin.tie(0);
cout.tie(0);
dfs(1,0);
cout<<ans;
return 0;
}
DP做法:
前面分析出:对于一道题,要么答对,分数+10;要么答错,分数清0。如果要得到70分,一定是连续答对7道题,是在答对前一道题的60分基础上再答对一道题,而60分又是在答对前一道题的50分基础上,这样一直递推,可以得出我们的dp数组应该是一个二维的(因为我们需要一维来跟踪记录分数,在第七道题开始的每一道题都可能得到70分,还需要一维来记录)——dp[i][j],i一个表示第几道题,j另一个表示得到多少分,也就是第i道题能获得j分的情况数。
递推公式借用一下题解区的图:
特别注意:在第i道题做错的那里,只能累加到9分,因为取到10会结束,不能再递推下去
代码(DP):
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 30+10;
int ans = 0;
//将100等价成10表示
int dp[N][15]={0};
signed main() {
cin.tie(0);
cout.tie(0);
//第一道题答错或者答对都是一种情况
dp[1][0]=1,dp[1][1]=1;
for(int i=2;i<=30;i++){
for(int j=0;j<=9;j++){
if(j==0){
for(int k=0;k<=9;k++)//特别注意这里只能取到9,因为取到10会结束,不能在递推下去
dp[i][j]+=dp[i-1][k];
}else{
dp[i][j]+=dp[i-1][j-1];
}
}
}
for(int i=7;i<=30;i++){
ans+=dp[i][7];
}
cout<<ans;
return 0;
}