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
",--A);
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/7887155.html