[POJ] 1948 Triangular Pastures (DP)
题目地址:http://poj.org/problem?id=1948
题目大意:
给N条边,把这些边组成一个三角形,问面积最大是多少?必须把所有边都用上。
解题思路:
根据题意周长c已知,求组合三边长使得三角形面积最大。如果直接DFS的话,每次考虑每根木棍放在哪一条边上,爆搜,可以加上每条边不会大于周长的一半的剪枝。根据数据规模,仍会超时,所以可以考虑采用动态规划。因为周长c已知,所以只需考虑其中两条边即可。类似二维0-1背包的做法,开一个二维判定数组f[i][j],i代表第一条边长为i,j为第二条边长为j,则第三条边长为c-i-j,判定所有情况。最后验证即可。因为三角形每条边长不可能超过周长的一半,所以枚举i,j最大到c/2即可。最后注意结果小数部分不是四舍五入,而是直接截断的,所以可以利用强制转化。
DP代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> using namespace std; const int N=41*41; int f[N][N]; int a[41],c=0,n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); c+=a[i]; } memset(f,0,sizeof(f)); f[0][0]=1; for(int i=1;i<=n;i++){ for(int j=c/2+1;j>=0;j--){ for(int k=c/2+1;k>=0;k--){ if(j-a[i]>=0 && f[j-a[i]][k]){ f[j][k]=1; } if(k-a[i]>=0 && f[j][k-a[i]]){ f[j][k]=1; } } } } double s=0; for(int i=c/2+1;i>=0;i--){ for(int j=c/2+1;j>=0;j--){ if(f[i][j]){ double la=i,lb=j,lc=c-i-j; double p=(la+lb+lc)/2.0; if(sqrt(p*(p-la)*(p-lb)*(p-lc))>s){ s=sqrt(p*(p-la)*(p-lb)*(p-lc)); } } } } printf("%d\n",s==0 ? -1 : (int)(s*100)); return 0; }
DFS代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> using namespace std; const int N=53; int n,sum,la=0,lb=0,c=0,lc; int a[N],f[N]; double s=0; void dfs(int k) { if(la>c/2 || lb>c/2 || lc>c/2) return ; if(k==n){ if(la+lb>lc && la+lc>lb && lb+lc>la){ double p=(la+lb+lc)/2.0; if(sqrt(p*(p-la)*(p-lb)*(p-lc))>s){ s=sqrt(p*(p-la)*(p-lb)*(p-lc)); } } return ; } for(int i=0;i<n;i++){ if(!f[i]) for(int j=0;j<3;j++){ if(j==0){ la+=a[i]; f[i]=1; dfs(k+1); f[i]=0; la-=a[i]; } if(j==1){ lb+=a[i]; f[i]=1; dfs(k+1); f[i]=0; lb-=a[i]; } if(j==2){ lc+=a[i]; f[i]=1; dfs(k+1); f[i]=0; lc-=a[i]; } } } } int main() { memset(f,0,sizeof(f)); scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); c+=a[i]; } dfs(0); printf("%d\n",s==0 ? -1:(int)(s*100)); return 0; }