终于找到一点自信,没有看别人题解ac这道lrj紫书上的题目,一旦想到用海伦公式其他的就很简单了,我发现用递归写dp,真的比循环写dp要容易些。主要思路就是dfs函数中的循环语句。其实这道题目也可以看做搜索类的题目,状态转移方程式是dp[i][j][n]表示在i,j点中取n个节点的最大面积(i,j必取),dp[i][j][n] = max(dp[k][j][n-1]+area[i][k][j]) 其中i+1<= k <= j-1.就是这样简单的思路,有点想石子合并中一些思路。
题目链接:https://vjudge.net/problem/UVA-1543
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double pi = 3.14159265358979323846;
const int maxn = 60;
int n , m;
double point[maxn];
double area[maxn][maxn][maxn];
double dp[maxn][maxn][maxn];
double getangle (int i , int j) {
double tmp = abs(point[i]-point[j]);
return tmp > 0.5 ? 1-tmp : tmp;
}
double getarea (int i , int j , int k) {
double aij = getangle(i,j)*pi , ajk = getangle(j,k)*pi , aki = getangle(k,i)*pi;
double eij = sin(aij)*2 , ejk = sin(ajk)*2 , eki = sin(aki)*2;
double p = (eij+ejk+eki)/2;
return sqrt(p*(p-eij)*(p-ejk)*(p-eki));
}
void initarea () {
for (int i = 1 ; i <= n ; i++)
for (int j = i+1 ; j <= n ; j++)
for (int k = j+1 ; k <= n ; k++) area[i][j][k] = getarea(i, j, k);
}
double dfs (int i , int j , int n) {
double ans = 0;
if (dp[i][j][n]) return dp[i][j][n];
if (n == 0) return 0;
for (int k = i+1 ; k <= j-1 ; k++)
if (j-k > n-1) ans = max(ans , dfs(k, j, n-1)+area[i][k][j]);
return dp[i][j][n] = ans;
}
int main () {
while (scanf("%d%d" , &n , &m) != EOF && n && m) {
memset(area,0,sizeof(area));
memset(dp,0,sizeof(dp));
memset(point,0,sizeof(point));
double ans = 0;
for (int i = 1 ; i <= n ; i++) scanf("%lf" , &point[i]);
initarea();
for (int i = 1 ; i <= n ; i++)
for (int j = i+m-1 ; j <= n ; j++) ans = max(ans , dfs(i,j,m-2));
printf ("%.6lf\n" , ans);
}
}