[背包DP] 洛谷P1284 三角形牧场(已知推未知的状压DP)

题目

LP1284

思路

首先本题是一个判断DP,那么就考虑指标函数如下定义:
d == 0:不存在, d == 1:可以构成边, d == 2:可以构成三角形。
那么就是状态的定义问题,刚开始我想到的是d(i,j,k),分别表示三角形三边。但这样发现1600^3会MLE,所以不可取。
由于根据边的总和s可以根据两边求出第三边,所以这里三边都表示是没有必要的,这里跟技巧枚举那里有点相似,根据已知量能推出来的未知量就不要再枚举/作为状态了
技巧枚举可以参考:12

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int maxn = 40 + 10;
const int maxm = 1600 + 10;
int n, v[maxn], d[maxm][maxm];
// d == 0:不存在, d == 1:可以构成边, d == 2:可以构成三角形

bool tri(int a, int b, int c) {
    return a + b > c && a + c > b && b + c > a;
}

int main() {
    scanf("%d", &n);
    int s = 0;
    _rep(i, 1, n) { scanf("%d", &v[i]); s += v[i]; }

    d[0][0] = 1;
    _rep(i, 1, n)
        for (int j = s; j >= 0; j--)
            for (int k = s; k >= 0; k--)
                if (d[j][k]) {
                    int len = s - j - k;
                    if (j + v[i] <= s) {
                        if (tri(j + v[i], k, len-v[i])) d[j + v[i]][k] = 2;
                        else d[j + v[i]][k] = 1;
                    }
                    if (k + v[i] <= s) {
                        if (tri(j, k + v[i], len-v[i])) d[j][k + v[i]] = 2;
                        else d[j][k + v[i]] = 1;
                    }
                }

    double ans = 0.0;
    _rep(j, 1, s) _rep(k, 1, s) if (d[j][k] == 2) {
        int len = s - j - k;
        double p = (len + j + k) / 2.0;
        ans = max(ans, sqrt(p*(p - len)*(p - j)*(p - k)));
    }
    if (ans != 0.0) printf("%.0lf\n", floor(ans * 100));
    else printf("-1\n");

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81145185