题意略。
思路:
本题开始我先写了一发dfs暴力,然而递归程度太深,导致爆栈。仔细回想一下dfs的过程,发现最不好处理的就是每收集到3个木棍,才能构成一个三角形。
并且,还有一个隐患就是不能完全枚举出来木棍的组合情况。那么我们可以预先把木棍的组合情况枚举出来,按照题意,不会超过220种现在我们就是
想在这些组合情况中谋求最大面积。这样,我们可以把这个题看成为一个特殊的背包问题。
令dp[i][state]为在0~i中,当前恰好持有的木棍情况为state,且这些木棍要全部用完,我可以谋取的最大利益。那么状态转移方程为:
dp[i][state] = max(dp[i - 1][state],dp[i - 1][state - 当前方案所需木棍情况] + area);
详见代码:
#include<bits/stdc++.h> #define maxn 251 #define maxn1 5000 using namespace std; struct node{ double val; int state; node(double a = 0,int b = 0){ val = a,state = b; } }; double store[15]; node depot[maxn]; double dp[2][maxn1]; int n; double cal(double a,double b,double c){ double p = (a + b + c) / 2; return sqrt(p * (p - a) * (p - b) * (p - c)); } bool judge(double a,double b,double c){ return (fabs(a - b) < c && c < a + b); } void depart(int s){ for(int i = 0;i < n;++i){ if(s & (1<<i)) printf("1"); else printf("0"); } } int main(){ while(scanf("%d",&n) == 1 && n){ for(int i = 0;i < n;++i) scanf("%lf",&store[i]); int tail = 0; for(int i = 0;i < n;++i){ for(int j = i + 1;j < n;++j){ for(int k = j + 1;k < n;++k){ double a = store[i],b = store[j],c = store[k]; if(!judge(a,b,c)) continue; depot[tail++] = node(cal(a,b,c),(1<<i) | (1<<j) | (1<<k)); } } } for(int i = 0;i < 2;++i){ for(int j = 0;j < maxn1;++j) dp[i][j] = -1; } dp[0][depot[0].state] = depot[0].val; dp[0][0] = 0; int total = (1<<n); for(int i = 1;i < tail;++i){ for(int s = 0;s < total;++s){ dp[i & 1][s] = dp[(i - 1) & 1][s]; if(depot[i].state != (s & depot[i].state) || dp[(i - 1) & 1][s - depot[i].state] == -1) continue; dp[i & 1][s] = max(dp[i & 1][s],dp[(i - 1) & 1][s - depot[i].state] + depot[i].val); } } double ans = 0; for(int s = 0;s < total;++s){ ans = max(ans,dp[(tail - 1) & 1][s]); } printf("%.2lf ",ans); } return 0; }