每日一题之 hiho1794 拼三角形 (状压dp)

描述
给定 n 根木棍,第 i 根长度为 ai

现在你想用他们拼成尽量多的面积大于 0 的三角形,要求每根木棍只能被用一次,且不能折断

请你求出最多能拼出几个

输入
第一行一个正整数 n

第二行 n 个正整数 a1 … an

1 ≤ n ≤ 15

1 ≤ ai ≤ 109

输出
输出最多能拼出几个三角形

样例输入
6
2 2 3 4 5 6
样例输出
2

思路:

一开始看n这么小,以为是暴力,结果不行,看了一眼题解,才知道是状压dp,之前一只没明白过,现在终于懂了。
大致是用二进制表示某个位置取或不取,这样一串01串可以表示n个位置每个点的状态了。对于这个题目,我们需要枚举能组成三角形的情况,然后记录构成三角形的时候选了哪三条边。然后状压dp

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = (1<<15)+5;

int dp[maxn];
int state[maxn];
bool judge(long long a, long long b, long long c)
{
    if ( a+b > c && c - a < b) return true;
    return false;
}

int main()
{   

    long long A[20];
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i)
        cin>>A[i];
    sort(A,A+n);
    int res = 0;
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = i+1; j < n; ++j) {
            for (int k = j+1; k < n; ++k) {
                if (judge(A[i],A[j],A[k])) {
                    state[++cnt] = (1<<i)|(1<<j)|(1<<k);
                }
            }

        }

    }

    dp[0] = 1;

    for (int i = 1; i <= cnt; ++i) {
        for (int j = (1<<n) - 1; j >= 0; --j) {
            if(dp[j] && !(j&state[i])) {
                dp[j|state[i]] = dp[j] + 1;

                res = max(res,dp[j]);
            } 
        }
    }

    cout << res << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014046022/article/details/81295853