牛客竞赛ACM模式C++代码报错记录
题目是动态规划的练习题1001-方块与收纳盒。源代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int s[100];
int dp(int n){ //记忆化搜索版本
int ans;
if(s[n] != 0)
return s[n];
else
{
if(n == 0)
return 1;
if(n == 1)
return 1;
if(n > 1)
return s[n] = dp(n-1) + dp(n-2);//因为dp函数是有返回值的,通过这样进行递归调用计算
}
}
int main(){
int T,n;
cin>>T;
while(T--){
int n;
cin>>n;
memset(s, 0, sizeof(s));//该步骤不能再在全局执行
cout<<dp(n)<<endl;
}
return 0;
}
报错信息:
编译错误:您提交的代码无法完成编译
a.cpp:16:2: error: non-void function does not return a value in all control paths [-Werror,-Wreturn-type]
}
^
a.cpp:17:1: error: extraneous closing brace (‘}’)
}
^
2 errors generated.
但本地DevC++是可以正常运行的,读了下错误信息是说不是所有的控制路径都有返回值,应该是dp函数里面的问题,写的时候用了if-else返回值设置在了里面,最外层没有一个返回值,因此就判定成了缺少返回值。原本的用意是把记忆化搜素的思路列的更清楚一点,计算过就直接查表,没计算过再走流程,于是把else语句拆出来。
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int s[100];
int dp(int n){ //记忆化搜索版本
int ans;
if(s[n] != 0)
return s[n];
if(n == 0)
return 1;
if(n == 1)
return 1;
if(n > 1)
return s[n] = dp(n-1) + dp(n-2);//因为dp函数是有返回值的,通过这样进行递归调用计算
}
int main(){
int T,n;
cin>>T;
while(T--){
int n;
cin>>n;
memset(s, 0, sizeof(s));//该步骤不能再在全局执行
cout<<dp(n)<<endl;
}
return 0;
}
但依然报错:
编译错误:您提交的代码无法完成编译
a.cpp:17:1: error: non-void function does not return a value in all control paths [-Werror,-Wreturn-type]
}
^
1 error generated.
最后只得:
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int s[100];
int dp(int n){ //记忆化搜索版本
int ans;
if(s[n] != 0)
return s[n];
if(n == 0)
return 1;
if(n == 1)
return 1;
if(n > 1)
s[n] = dp(n-1) + dp(n-2);
return s[n];//因为dp函数是有返回值的,通过这样进行递归调用计算
}
int main(){
int T,n;
cin>>T;
while(T--){
int n;
cin>>n;
memset(s, 0, sizeof(s));//该步骤不能再在全局执行
cout<<dp(n)<<endl;
}
return 0;
}
终于是编译通过了,样例也过了,但提交后只通过了50%的样例。
答案错误
用例通过率为 50%
运行时间 3ms
占用内存 396KB
分析下原因:对于代码的思路是对于收纳盒的最后一个位置,第n个小格子,填满它的方式有两种,而这取决于第n-1个格子的填充方式,如果第n-1个格子是由2连方块填满的,则第n个格子只能用单个方块填,如果第n-1个格子是由单个方块填满的,那么第n个格子也只能用单个方块填,因此第n个格子的填充方式就是第n-1格的填充方式决定的,而使用2连方块填充时实际上n-1格又是由第n-2格所确定的,因此得到递推式:
dp[n] = dp[n-1] + dp[n-2];
检查了一下发现没有给s[0]和s[1]赋初值,虽然从结果来看问题也不出在这里但是严谨起见改一下。
输入边界值发现了问题,题目中最大值是80,虽然写的时候有一晃而过的这个值这么小是不是有猫腻但是没有细算,应该是越界了,把样例改了一下果然越界了,把数据类型改long long,本地测了一下通过了。
提交后AC的代码(相比之前又改掉一些冗余的定义):
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
typedef long long ll;
ll s[N];
ll dp(int n){ //记忆化搜索版本
if(s[n] != 0)
return s[n];
else{
if(n == 0)
s[n] = 1;
if(n == 1)
s[n] = 1;
if(n > 1)
s[n] = dp(n-1) + dp(n-2);//因为dp函数是有返回值的,通过这样进行递归调用计算
}
return s[n];
}
int main(){
int T,n;
cin>>T;
while(T--){
int n;
cin>>n;
memset(s, 0, sizeof(s));//该步骤不能再在全局执行
cout<<dp(n)<<endl;
}
return 0;
}
答案正确
通过全部用例
运行时间 4ms
占用内存 448KB
运行时间稍慢一点,看了下题目总提交,稍稍优化了一下快了一点内存占用也小了一些:
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
typedef long long ll;
ll s[N];
ll dp(int n){ //记忆化搜索版本
if(s[n] != 0)
return s[n];
if(n == 0)
s[n] = 1;
if(n == 1)
s[n] = 1;
if(n > 1)
s[n] = dp(n-1) + dp(n-2);//因为dp函数是有返回值的,通过这样进行递归调用计算
return s[n];
}
int main(){
int T,n;
cin>>T;
while(T--){
int n;
cin>>n;
memset(s, 0, sizeof(s));//该步骤不能再在全局执行
cout<<dp(n)<<endl;
}
return 0;
}
答案正确
通过全部用例
运行时间 3ms
占用内存 396KB
突然想到其实最大就是80,完全可以全都算出来直接查表()
但是改完之后并没有快特别多:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll s[81];
void dp(){ //记忆化搜索版本
s[0] = 1;
s[1] = 1;
for(int i = 2; i <= 80; i++)
s[i] = s[i-1] + s[i-2];
}
int main(){
int T,n;
cin>>T;
dp();
while(cin>>n){
cout<<s[n]<<endl;
}
return 0;
}
答案正确
通过全部用例
运行时间 3ms
占用内存 424KB
2ms到底怎么做到的哇,不用函数也还是3ms。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll s[81];
int main(){
int T,n;
cin>>T;
s[0] = 1;
s[1] = 1;
for(int i = 2; i <= 80; i++)
s[i] = s[i-1] + s[i-2];
while(cin>>n){
cout<<s[n]<<endl;
}
return 0;
}
答案正确
通过全部用例
运行时间 3ms
占用内存 396KB