应该也是USACO的题目?同样没有找到具体出处。
【题目大意】
和所有人一样,奶牛喜欢变化。它们正在设想新造型牧场。奶牛建筑师Hei想建造围有漂亮白色栅栏的三角形牧场。她拥有N(3≤N≤40)块木板,每块的长度L(1≤L≤40)都是整数,她想用所有的木板围成一个三角形使得牧场面积最大。
请帮助Hei小姐构造这样的牧场,并计算出这个最大牧场的面积。
[输入]
第1行:一个整数N。
第2行起:包含N个用空格分隔的整数,即是每块木板的长度。
[输出]
仅一个整数:最大牧场面积乘以100然后舍尾的结果。如果无法构建,输出-1。
[样例输入]
mr355.in
5
1 1 3 3 4
[样例输出]
692
【思路】
二维背包问题,dp[i][ja][jb],取到第i块木板时能否组成ja、jb长度。预处理时,dp[0][0][0]=1,即取到第0块木板做成两边长度为0是可能的。这里有一个优化,tot表示当前已经取到的i块木板的总长度,ja、jb的长度判断只需从0..tot,如果当前dp[i-1][ja][jb]能取到,则dp[i][ja][jb],dp[i][ja+leng][jb],dp[i][ja][jb+leng]均能取到。这个时候我们发现,当前的dp[i]只和dp[i-1]相关,所以可以更改成滚动数组。
最后依次枚举前两边长度,并相减得出最后一边长度,如果能够组成三角形,则用海伦公式算出面积与最小值比较。
【易错点】
注意精度问题!double p=(a+b+c)*1.0/2,一定不能忘记要乘上0.1,否则会被视作整除去尾掉的!
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 const int MAXN=40+5; 6 int n,tot; 7 int leng[MAXN]; 8 int dp[2][1600][1600]; 9 /*取到第几块木板,后面为前两块木板,这里用了滚动数组*/ 10 11 void init() 12 { 13 scanf("%d",&n); 14 for (int i=0;i<n;i++) scanf("%d",&leng[i]); 15 } 16 17 void dpprocess() 18 { 19 memset(dp,0,sizeof(dp)); 20 dp[0][0][0]=1; 21 tot=0; 22 /*当前已经取到的木块总长度*/ 23 for (int k=0;k<n;k++) 24 { 25 for (int i=0;i<=tot;i++) 26 for (int j=i;j<=tot-i;j++) 27 { 28 if (dp[k%2][i][j]==1) 29 { 30 dp[(k+1)%2][i][j]=1; 31 dp[(k+1)%2][i+leng[k]][j]=1; 32 dp[(k+1)%2][i][j+leng[k]]=1; 33 } 34 } 35 tot+=leng[k]; 36 } 37 } 38 39 void print() 40 { 41 int ans=-1; 42 for (int a=0;a<=tot;a++) 43 for (int b=a;b<=tot-a;b++) 44 { 45 if (dp[n%2][a][b]==1) 46 { 47 int c=tot-a-b; 48 if (a<b+c && b<a+c && c<a+b) 49 { 50 double p=(a+b+c)*1.0/2; 51 double s=sqrt(p*(p-a)*(p-b)*(p-c))*100; 52 if (s>ans) 53 { 54 ans=s; 55 } 56 } 57 } 58 } 59 cout<<ans<<endl; 60 } 61 62 int main() 63 { 64 freopen("mr355.in9","r",stdin); 65 freopen("mr355.ou9","w",stdout); 66 init(); 67 dpprocess(); 68 print(); 69 return 0; 70 }
时间: 2024-09-30 11:17:29