2021.8.11提高B组模拟3T1 积木(乱糊暴搜)(正解:状压dp)

Posted SSL_LKJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021.8.11提高B组模拟3T1 积木(乱糊暴搜)(正解:状压dp)相关的知识,希望对你有一定的参考价值。

积木

题目大意

输入样例

3
8 7 6
3 9 4
1 10 5

输出样例

18

题目数据

解题思路

暴搜就没什么好讲的了

原本以为只有40,AC了就离谱

(数据真水)


正文:状压dp

前提:我这个dp,积木的摆放是先上后下的,所以可能和题目所表达的意思有些相反

f i , j , a , b f_i,_j,_a,_b fi,j,a,b 为当前状态为i(01串,1表示有,0表示没有),上一个放置的积木为 j,a、b为摆放的方式

共有 6 种

假设长方体为 a ∗ b ∗ c a*b*c abc

abc
acb
bca
bac
cab
cba

易得出转移方程

//每种情况都要判断
if(x[k]>=xx&&y[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][1]+zz);
if(x[k]>=xx&&z[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][2]+zz);
if(y[k]>=xx&&z[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][3]+zz);
if(y[k]>=xx&&x[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][1]+zz);
if(z[k]>=xx&&x[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][2]+zz);
if(z[k]>=xx&&y[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][3]+zz);

其中 x k 、 y k 、 z k x_k、y_k、z_k xkykzk上面对应 a 、 b 、 c a、b、c abc,则新放的

x x 、 y y 、 z z xx、yy、zz xxyyzz上一种情况 a 、 b 、 c a、b、c abc,则当前的

五重循环,其中四重为 i 、 j 、 a 、 b i、j、a、b ijab,另外一个为 k k k,为新放的积木,作用同 j j j

AC代码(两个)

1.暴搜(dfs)莫名AC

#include<iostream>
#include<cstdio>
using namespace std;
int n,mmax,a[20],b[20],c[20],v[20];
bool check(int x,int y,int xx,int yy)//判断是否能放上去

	if(x<=xx&&y<=yy)return 1;
	if(x<=yy&&y<=xx)return 1;
	return 0;

void dfs(int x,int ans,int aa,int bb)

	mmax=max(mmax,ans);//随时更新
	if(x==n)return;
	for(int i=1;i<=n;i++)
		if(!v[i])
		
			if(check(a[i],b[i],aa,bb))//一一判断
				v[i]=1,dfs(x+1,ans+c[i],a[i],b[i]),v[i]=0;			
			if(check(a[i],c[i],aa,bb))
				v[i]=1,dfs(x+1,ans+b[i],a[i],c[i]),v[i]=0;			
			if(check(b[i],c[i],aa,bb)) 
				v[i]=1,dfs(x+1,ans+a[i],b[i],c[i]),v[i]=0;			
		
	return;

int main()

	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
	dfs(0,0,100000000,100000000);
	printf("%d",mmax);
	return 0;


2.正解:状压dp

#include<iostream>
#include<cstdio>
using namespace std;
int n,mmax,x[20],y[20],z[20],f[40005][20][5][5];
int main()

	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	
		scanf("%d%d%d",&x[i],&y[i],&z[i]);
		f[1<<i-1][i][1][1]=z[i];//初值(6种方式摆放)
		f[1<<i-1][i][1][2]=y[i];
		f[1<<i-1][i][1][3]=x[i];
		f[1<<i-1][i][2][1]=z[i];
		f[1<<i-1][i][2][2]=y[i];
		f[1<<i-1][i][2][3]=x[i];
		mmax=max(mmax,max(x[i],max(y[i],z[i])));//初值
	
	for(int i=1;i<1<<n;i++)
		for(int j=1;j<=n;j++)
			if(((1<<j-1)&i)!=0)//判断j是否在i中存在
			
				int o=i-(1<<j-1),xx,yy,zz;//o为移走j后,剩下的积木情况
				for(int a=1;a<=2;a++)//6种方式摆放
					for(int b=1;b<=3;b++)
					
						if(a==1)
						
							if(b==1)xx=x[j],yy=y[j],zz=z[j];
							if(b==2)xx=x[j],yy=z[j],zz=y[j];
							if(b==3)xx=y[j],yy=z[j],zz=x[j];
						
						else
						
							if(b==1)xx=y[j],yy=x[j],zz=z[j];
							if(b==2)xx=z[j],yy=x[j],zz=y[j];
							if(b==3)xx=z[j],yy=y[j],zz=x[j];
						
						for(int k=1;k<=n;k++)//再重新放一个上去
						
							int oo=(1<<k-1)&o;
							if(oo!=0)//判断是否放过,没有则继续
							//每种情况都要判断
								if(x[k]>=xx&&y[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][1]+zz);
								if(x[k]>=xx&&z[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][2]+zz);
								if(y[k]>=xx&&z[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][1][3]+zz);
								if(y[k]>=xx&&x[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][1]+zz);
								if(z[k]>=xx&&x[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][2]+zz);
								if(z[k]>=xx&&y[k]>=yy)f[i][j][a][b]=max(f[i][j][a][b],f[o][k][2][3]+zz);
								mmax=max(f[i][j][a][b],mmax);	//随时更新
							
						
					
			
	printf("%d",mmax);
	return 0;


谢谢

以上是关于2021.8.11提高B组模拟3T1 积木(乱糊暴搜)(正解:状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

2021.7.14提高B组模拟3T1 树的直径(lca)(倍增)

2021.7.14提高B组模拟3T2 积木 (dp)

2021.8.11提高B组模拟3T2 + P2323 [HNOI2006] 公路修建问题(并查集)

2021.8.11提高B组模拟3T2 + P2323 [HNOI2006] 公路修建问题(并查集)

2021.8.14提高B组模拟6T3 + P7527 [USACO21OPEN] United Cows of Farmer John (树状数组)

2021.8.14提高B组模拟6T3 + P7527 [USACO21OPEN] United Cows of Farmer John (树状数组)