比赛时,这个不是我所负责的题目,队友写深搜,结果T全场,晚上请教何老师以后用一个知道了求集合子集的快速方法才得以解决
首先预处理出每种组合的总长度,因为三角形中最短的一边长度一定小于等于总长度的三分之一,所以hash过去分为hash值/50000和hash值%50000两个部分就行了,枚举每种组合,判断是否能够构成三角形,能的话判断是否重复,未出现重复则答案加1,否则舍弃
#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
int n,i,s[32768],maxn,f[15],t,j,sett,a,b,c,k,ans;
set <int> S;
int p;
int main()
{
scanf("%d",&t);
while(t--)
{
S.clear();
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&f[i]);
maxn=(1<<n);
for(i=0;i<maxn;i++)
{
s[i]=0;
for(j=0;j<n;j++)
if(i&(1<<j))s[i]+=f[j];
}
ans=0;
for(i=1;i<maxn;i++)
{
sett=(maxn-1)^i;
for(j=sett;j!=0;j=(j-1)&sett)
{
a=s[i],b=s[j],c=s[sett^j];
if(b<a)
{
k=b;
b=a;
a=k;
}
if(c<a)
{
k=c;
c=a;
a=k;
}
if(c<b)
{
k=c;
c=b;
b=k;
}
if(a+b>c && a+c>b && b+c>a)
{
p=a*70000+b;
if(S.find(p)==S.end())
{
ans++;
S.insert(p);
}
}
}
}
printf("%d\n",ans);
}
return 0;
}