智商
最近做的一道催眠题~
(_ _)( - . - )(~ O~)……( - . - )
智商测试…… 有 N 个木棍,每个木棍有一个长度 Ai,任务是找出能组成的三角形的最大面积 S 是多少。
Input 第 1 行:一个整数 N,表示有 N 个木棍。 第 2~N+1 行:每行一个整数 Ai,表示第 i 个木棍的长度。
Output 一行一个整数,最大面积 S*100 后向下取整
如果不能组成三角形则输出 -1。
对于 10%的数据:N <= 3
对于 30%的数据:N <= 10
对于 100%的数据:3 <= N <= 40 , Ai<=40
已知三角形三边长度 a,b,c,可使用海伦公式计算面积:
p=(a+b+c)]/2
以下是心理路程ε=(´ο`*)))
首先~没有思路时就按照肉眼可见不用思考的线索进行实用的瞎捣鼓╭(╯^╰)╮
那么先做一个计算面积的函数方便之后调用
(^-^)V
根据公式可以很容易的做出♪(^ ∇^ * ):
double calc(int a,int b,int c)
{
double p=(a+b+c)/2.0;
return sqrt(p*(p-a)(p-b)(p-c));
}
因为要开根啊什么的就用double吧,精确一点
在接下来的运算中可以按照要求
S *100 后向下取整( * ^ ▽^ *)
头文件不能用万能时,把能想到的都写上方便以后用(个人懒习惯(*^▽ ^ *))
#include < iostream>
#include < cstdio>
#include < cctype>
#include < cstdlib>
#include < cmath>
#include < ctime>
#include < string>
#include < algorithm>
#include < queue>
using namespace std;
然后,打上一个框架~
这里回顾一下输入输出
Input 第 1 行:一个整数 N,表示有 N 个木棍。 第 2~N+1 行:每行一个整数 Ai,表示第 i 个木棍的长度。
Output 一行一个整数,最大面积 S*100 后向下取整如果不能组成三角形则输出 -1。
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);}
printf("%d\n",res);
return 0;
}
接下来捋一捋思路( ^ o^ )/~
有 N 个木棍,每个木棍有一个长度 Ai,任务是找出能组成的三角形的最大面积 S 是多少。
“最大”划重点啊^ _ ^
找最大的话,要么是最优,要么是比出来的
鉴于最优通常很费脑子,那就先比一比试试吧︿( ̄︶ ̄)︿
既然要比,那就枚举吧,挨个枚举面积
由公式可得面积是由边长可得,那么以边长为条件枚举吧
怎么以边长为条件呢
啊,忽略了一个小条件w(゚Д゚)w
“ 如果不能组成三角形则输出 -1。”
那么,首先判定是否能组成一个三角形
用一个bool数组进行记载好了,是为true,否为false
(^-^)V
数组当然是越小越好,,,,,,,,,,,,,,,,,,,,,
而如果以边为条件,,,,,,,
似乎应该是三条边对应三维数组?
(⊙o⊙)…一看就要爆栈的样子
那么如何简化呢,去掉一条边的条件什么的(ノ`Д)ノ
(キ`゚Д゚´)!!可以用另外两条边来象征第三边啊
只要知道到周长C,
即可得a3=C-a1-a2;
那么周长无疑就是棍棍总长了,在记录每根棍棍长度时顺便记录就好了(^o ^)/~
申请一个全局变量total(这样会自动初始化为0吖)
真是懒人福利(。-ω-)zzz
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);total+=a[i];}
顺便把数组也设置成全局变量好了(^ o^)/~
const int N=40+10;
bool f[NN][NN];
//f[a][b]表示能否构成一个边长为a,b,c的三角形(c=tot-a-b)
这时也能顺便完成枚举的版块了
int res=-1;
for(int i=0;i<=total;i++)
for(int j=0;j<=total;j++)
{
if(!f[i][j]) continue;
int k=total-i-j;
res=std::max(res,(int)(calc(i,j,k)*100));
}
输出也好啦~ printf("%d\n",res);
接下来是大头了ε=(´ο`*))):
论如何枚举找到可行的组合方式
这就需要灵感了╭(╯^╰)╮
在这个工程中真是很容易犯困的(ノ`Д)ノ
。。。
(最后还是听老师讲的(差点睡着(@_@)))
周长是一定的,以小棍棍作为线索
当这条边多一根小棍棍时,那条边就少一条小棍棍,三角形仍然成立吗?
原先:a、b、c 同时a+b>c
后来:a+小棍棍、b-小棍棍、c
此时a+小棍棍+b-小棍棍
仍然>c
同理就可以逆向使用了(^-^)V
if(j>=a[i] && f[j-a[i]][k]) f[j][k]=1;
if(k>=a[i] && f[j][k-a[i]]) f[j][k]=1;
枚举条件首先是小棍棍
for(int i=1;i<=n;i++)
然后是两条边
for(int j=total;j>=0;j--)
for(int k=total;k>=0;k--)
搞定O(∩_∩)O!
接下来理一理就是完整代码了~
```cpp
```cpp
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int N=40+10;
int n,a[N],total=0;
bool f[N*N][N*N];//f[a][b]表示能否构成一个边长为a,b,c的三角形(c=tot-a-b)
double calc(int a,int b,int c)//海伦公式
{
double p=(a+b+c)/2.0;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);total+=a[i];}
f[0][0]=1;
for(int i=1;i<=n;i++)//枚举找到可行的组合方式:i(枚举棍棍)
for(int j=total;j>=0;j--)//j、k(对长度进行设置枚举)
for(int k=total;k>=0;k--)
{
if(j>=a[i] && f[j-a[i]][k]) f[j][k]=1;
if(k>=a[i] && f[j][k-a[i]]) f[j][k]=1;
}
int res=-1;
for(int i=0;i<=total;i++)
for(int j=0;j<=total;j++)
{
if(!f[i][j]) continue;
int k=total-i-j;
res=std::max(res,(int)(calc(i,j,k)*100));
}
printf("%d\n",res);
return 0;
}`