拼三角形(csustoj2010)

拼三角形
Description

Cwolf9有n根木棍,他现在想将他们拼成一些三角形,问最多能拼成多少三角形,每根木棍只能用一次。

Input
多组输入

每组数据第一行一个数 nn, (1 \leq n \leq 18)(1≤n≤18)。表示有n根木棍。

接下来一行,nn个数记为a_ia
i

。表示第ii根木棍的长度为1\le a_i\le 1001≤a
i

≤100

Output
对于每组数据每行输出一个数,表示用这nn根木棍可以拼出多少三角形。

Sample Input 1

6
2 2 3 4 5 6
6
2 3 8 2 3 9
5
2 3 3 4 5
Sample Output 1

2
2
1
Hint

nn不一定是3的倍数

https://csustacm.fun/problem/2010

思路: 算是很裸的状压dp了,首先算出所有合法状态,然后从所有合理的dp状态中选择不冲突的状态转移。一开始想的是排序后按顺序a + b > c的取,但是按这个规则,2 2 3 4 6 6只能取2 3 4,但实际可以取,2 6 6,2 3 4。比赛的时候写搜索然后t了,赛后标程搜索竟然只要4ms。。。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int state[1 << 18];
int dp[1 << 18];
int a[100];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i = 0;i < n;i++)
        {
            scanf("%d",&a[i]);
        }
        int cnt = 0;
        sort(a,a + n);
        for(int i = 0;i < n;i++)
        {
            for(int j = i + 1;j < n;j++)
            {
                for(int k = j + 1;k < n;k++)
                {
                    if(a[i] + a[j] > a[k])
                    {
                        state[cnt] = 0;
                        state[cnt] |= (1 << (n - i - 1));state[cnt] |= (1 << (n - j - 1));state[cnt] |= (1 << (n - k - 1));
                        cnt++;
                    }
                }
            }
        }
        
        memset(dp,-1,sizeof(dp));
        int ans = 0;
        dp[0] = 0;
        for(int i = 0;i < (1 << n);i++)
        {
            if(dp[i] != -1)
            {
                for(int j = 0;j < cnt;j++)
                {
                    if( (state[j] & i) == 0 )
                    {
                        dp[i | state[j]] = max(dp[i | state[j]],dp[i] + 1);
                        ans = max(ans,dp[i | state[j]]);
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(#,长沙理工大学,#,状态压缩)