18 校赛热身赛 C - Sometimes Naive (状态压缩)

Problem C. Sometimes Naive

Mr.Frog gets the N sticks, the length of the ith stick is Ai. He can divide the sticks into one or moregroups. He wanted to know how many groups are magical at most.

A group is magical that needs to meet the following condition: there are three sticks in this group exactly,and the three sticks can form a triangle.

Input

The first line is an integer T, indicating the number of cases.
For each test case, the first line contains one integer
N, where N is the number of stick.The second line contains N integers A1, A2, ..., AN, where Ai is the length of the ith stick.

Output

For each test case, output one line containing “Case #x: y”, where x is the test case number (startingfrom 1) and y is the answer.

Limits

1 T 20.
1 N 20.
1Ai 2×109.

Example

standard input
standard output

3
3
111
3
121
7
2 17 20 4 65 9 3

Case #1: 1
Case #2: 0
Case #3: 2

Note

For the first case, Mr.Frog can divide the sticks into a group {1, 1, 1} and it is magical, so you print 1.

For the second case, no matter how to divide the sticks, Mr.Frog can’t find any magical group, so youprint 0.

For the third case, Mr.Frog can divide the sticks into three groups {2, 3, 4}, {9, 17, 20} and {65}, thefirst and second group is magical, so you print 2. 


题意:有n条边,求边不能重复使用的情况下最多能组成多少个三角形


判断能否构成三角形:两边之和大于第三边

可以先枚举一下构成一个三角形的所有情况 C(3,n) ,因为k个三角形可以由k-1个三角形加上1个无重边的三角形组成,然后逐个找下去,直到找不到有k个三角形时,答案为k-1个三角形。

主要的问题转化为如何判断是否有重复使用同一条边的情况,可以利用状态压缩,每条边有01两种状态,判断是否有重边只需要按位与一下判断结果是否>0即可

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1<<21;
int T,n,a[25],num[25],cas = 0;
int b[N],vis[N];
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        if(n<3){
            printf("Case #%d: 0\n",++cas);
            continue;
        }
        memset(num,0,sizeof num);
        memset(vis,0,sizeof vis);
        sort(a,a+n);
        int cnt = 0, mx = n/3;
        for(int i=0;i<n-2;i++){
            for(int j=i+1;j<n-1;j++){
                for(int k=j+1;k<n;k++){
                    if(a[k]-a[j]<a[i]){
                        int sum = (1<<i) + (1<<j) + (1<<k);
                        b[cnt++] = sum; vis[sum] = 1;
                    }
                }
            }
        }
        num[2] = cnt;
        for(int i=2;i<=mx;i++){
            for(int j=num[i-1];j<num[i];j++){
                for(int k=0;k<num[2];k++){
                    if((b[k]&b[j])>0||vis[b[k]+b[j]]) continue;
                    vis[b[k]+b[j]] = 1; b[cnt++] = b[k]+b[j];
                }
            }
            num[i+1] = cnt;
        }
        int ans = 0;
        for(int i=1;i<=mx;i++) if(cnt>num[i]) ans = i;
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/w326159487/article/details/79631143
今日推荐