http://poj.org/problem?id=1948
(1)用dp[i][j] 表示三角形的边为 i, j 存在与否,本质是对枚举的优化(dp), 另外,上限可取sum/2;
(2)将 double p=sum/2.0 写错成 double p=sum/2,后果很严重;
(3)存在两种更新方式:
1)
for(i=1;i<=n;i++) for(j=sum/2;j>=0;j--) for(k=sum/2;k>=0;k--) { if(j>=a[i]) dp[j][k]=dp[j][k]||dp[j-a[i]][k]; if(k>=a[i]) dp[j][k]=dp[j][k]||dp[j][k-a[i]]; }
2)
for(i=1;i<=n;i++) for(j=0;j<=sum/2;j++) for(k=0;k<=sum/2;k++) if(dp[j][k]) dp[j+a[i]][k]=dp[j][k+a[i]]=1;
前者是直接考虑“自身”的更新,是正确的;后者是考虑对“别人”的更新,而有一部分的更新来不及实施。
相比而言,前者有较强的优越性,尤其是多重循环时。
具体代码:
View Code
#include<stdio.h> #include<math.h> #include<string.h> const int N=850; int n; int a[50], dp[N][N]; int main() { int i, j, k, sum; while(scanf("%d", &n)!=EOF) { sum=0; for(i=1;i<=n;i++) {scanf("%d", &a[i]); sum+=a[i];} memset(dp, 0, sizeof(dp)); dp[0][0]=1; for(i=1;i<=n;i++) for(j=sum/2;j>=0;j--) for(k=sum/2;k>=0;k--) { if(j>=a[i]) dp[j][k]=dp[j][k]||dp[j-a[i]][k]; if(k>=a[i]) dp[j][k]=dp[j][k]||dp[j][k-a[i]]; } int s=-1, x; for(i=1;i<=sum/2;i++) for(j=1;j<=sum/2;j++) if(dp[i][j]) { k=sum-i-j; if(i+j>k&&j+k>i&&k+i>j&&k>0) { double p=sum/2.0; x=sqrt(p*(p-i)*(p-j)*(p-k))*100; if(s<x) s=x; } } if(s==-1) printf("-1\n"); else printf("%d\n", s); } return 0; }
