在苏教版的五年级上册中,有一种经典的题目。
“给定一格点长方形,请问在该长方形中,有多少个小格点正方形与小格点长方形?” Hcode OnlineJudge
我对这个问题写出了代码:
#include<iostream>
using namespace std;
string s;
bool flag=1;
int n=0,m=0,sum,tmp1,tmp2;
int main(){
//输入并处理数据
cout << "长方形的宽:";
cin >> n;
cout << "长方形的长:";
cin >> m;
n=min(n,m);
m=max(n,m);
//正方形
for (int i=1;i<=n;i++)
sum+=(n-i+1)*(m-i+1);
cout << "这个长方形中有"<<sum << "个正方形。\n";
//长方形
for (int i=1;i<=m;i++){
tmp2+=i;
if (i==n)
tmp1=tmp2;
}cout << "这个长方形中有"<<tmp2*tmp1-sum << "个长方形(不包括正方形)\n";
return 0;
}
//输入并处理数据
cout << "长方形的宽:";
cin >> n;
cout << "长方形的长:";
cin >> m;
n=min(n,m);
m=max(n,m);
输入之后,为了方便,自动设成了n<m。
格点正方形数量的计算
//正方形
for (int i=1;i<=n;i++)
sum+=(n-i+1)*(m-i+1);
cout << "这个长方形中有"<<sum << "个正方形。\n";
正方形的计算方法是:
1×1正方形的个数+2×2正方形的个数+...+n×n正方形的个数。因为正方形的边长最大只能为小的n,不能是比n还要大的数。
而在计算正方形数量时,可以使用公式表示边长为i的格点正方形数量
f[i]=(n-i+1)*(m-i+1)
i表示正方形的边长。
在(n-i+1)中,计算的是正方形的边长在大长方形的宽上共有几种可能性。
在(m-i+1)中,计算的是正方形的边长在大长方形的长上共有几种可能性。
根据乘法原理“缺一不可”的原则,将其相乘,可以得到边长为i的正方形的个数。
最后全部相加,即可得到正方形的总个数。
长方形计算方式
长方形的通项公式推导相比起正方形的通项公式推导简单一些。
由于长方形的要求没有正方形那么苟刻,可以计算长与宽的可能性,最后再相乘。
//长方形
for(int i=1;i<=n;i++)
tmp1+=i;
for(int i=1;i<=m;i++)
tmp2+=i;
printf("这个长方形中有%d个长方形(不包括正方形)\n",tmp2*tmp1-sum);
//使用printf前请导入cstdio(C语言)库
(1+2+3+···+n-1+n)*(1+2+3+···+m-1+m)
这段代码是萌新的首选,毕竟简单又明了。但这题是NOIP1997的题目,就这样未免太没有水准了。我第一次提交的时候,就有几个测试点TLE了。所以,我们需要的是时间复杂度更优的,更快捷的代码。
因此我推导出了如此算法:
//长方形
for (int i=1;i<=m;i++){
tmp2+=i;
if (i==n)
tmp1=tmp2;
}
printf("这个长方形中有%d个长方形(不包括正方形)\n",tmp2*tmp1-sum);
//使用printf前请导入cstdio(C语言)库
由于在开始时已经设置了n<m,在这里就可以在计算m的累加时顺带计算n的累加。
在最后的算法,用tmp1×tmp2就可以得出总长方形的个数,非常没毛病。
但是,在这道题中有一道很关键的信息:不包括正方形的长方形。
因此我们需要把tmp1×tmp2的结果再减去正方形的总个数,也就是保存下来的sum。