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 a∗b∗c
长 | 宽 | 高 |
---|---|---|
a | b | c |
a | c | b |
b | c | a |
b | a | c |
c | a | b |
c | b | a |
易得出转移方程为
//每种情况都要判断
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 xk、yk、zk为上面对应的 a 、 b 、 c a、b、c a、b、c,则新放的
x x 、 y y 、 z z xx、yy、zz xx、yy、zz为上一种情况的 a 、 b 、 c a、b、c a、b、c,则当前的
五重循环,其中四重为 i 、 j 、 a 、 b i、j、a、b i、j、a、b,另外一个为 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.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 (树状数组)