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;
}