Jzoj4743 积木
由于n很小(<=15)我们考虑状态压缩
显然可以用三进制(雾)但是太浪费了
我们令f[i][j][s]表示现在已用的积木状态为S,最上面那个积木是第i个,其中这个积木的第j(0<=j<3)条边是竖着的(不在上表面)
转移的时候枚举i'和j‘判断一下即可
由于每个积木边长顺序没有影响所以可以先排序方便比较
#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int f[16][3][1<<16]={0},a[20][3]={{1<<30,1<<30,1<<30}},n,MS,A=0;
inline void max(int& x,int y){ x<y?x=y:0; }
inline bool ok(int i,int j,int x,int y){
int f[2],g[2],t1=0,t2=0;
for(int k=0;k<3;++k) if(k^j) f[t1++]=a[i][k];
for(int k=0;k<3;++k) if(k^y) g[t2++]=a[x][k];
return f[0]>=g[0] && f[1]>=g[1];
}
int main(){
scanf("%d",&n); MS=1<<n+1;
for(int i=1;i<=n;++i){
scanf("%d%d%d",a[i],a[i]+1,a[i]+2);
sort(a[i],a[i]+3);
}
f[0][0][1]=1;
for(int S=0;S<MS;++S)
for(int i=0;i<=n;++i)
for(int j=0;j<3;++j)
if(f[i][j][S])
for(int di=1;di<=n;++di)
if(!(S&(1<<di)))
for(int dj=0;dj<3;++dj)
if(ok(i,j,di,dj)) max(f[di][dj][S|(1<<di)],f[i][j][S]+a[di][dj]);
for(int S=0;S<MS;++S)
for(int i=0;i<=n;++i)
for(int j=0;j<3;++j) max(A,f[i][j][S]);
printf("%d\n",--A);
}