题意:
给出以最多6层的积木,每层可以由三个木块拼成,总共有三种颜色的木块,开始时给出了积木的排列情况,我们每次可以从积木中抽一块木块,抽木块的规则是投骰子,骰子分别投到red,blue,green,的概率为1/6,1/3,1/3.每次投骰子都要花费一分钟,如果投到的颜色不存在就等一分钟不操作。注意的是要保证不能从顶部抽,并且抽木块时不能让整个积木倒了,要保证不倒中间的木块必须存在,每次抽出的木块放到木块的顶部。现在要求到不能抽木块位置的时间期望。
题解:
这题要用状态压把整个积木的状态保存下来,但是很明显数组是存不了的,ll大小的状态量,那么我们考虑用hash来存,并且hash连同把dp的值也存进去。因为这题情况很多递推真心没法写啊,只能用记忆优化,搜索比较好操作点(算了,但我没说,搜索也很难写),用hash存状态的方法我只在插头dp中见到,这题真棒!在自己电脑上跑了7秒,在cf上竟然神一般1.9s。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef unsigned long long ll; const int oo=0x3f3f3f3f; const int SIZE=4000050; const int P=67; const int maxn=20; int a[maxn],b[maxn]; int F[260]; char str[10]; struct HASH{ int head[SIZE],next[SIZE]; ll state[SIZE]; double dp[SIZE]; int tol; void init(){ memset(head,-1,sizeof head); tol=0; } double find(ll s){ for(int i=head[s%SIZE];i!=-1;i=next[i]){ if(state[i]==s) return dp[i]; } return -1; } bool ins(ll s,double f){ if(find(s)>-1)return false; dp[++tol]=f; state[tol]=s; next[tol]=head[s%SIZE]; head[s%SIZE]=tol; return true; } }mat; ll Hash(int n){ for(int i=1;i<=n;i++)b[i]=a[i]; sort(b+1,b+n); ll s=0; for(int i=1;i<=n;i++){ s*=P; s+=b[i]; } return s; } inline void set_ST(int st[],int x){ st[0]=(x>>4)&3; st[1]=(x>>2)&3; st[2]=x&3; } inline int get_ST(int a,int b,int c){ if(a>c)swap(a,c);//小优化 return (((a<<2)+b)<<2)+c; } double dfs(int n){ ll s=Hash(n); double f=mat.find(s),c[4]={0,1e9,1e9,1e9}; if(f>-1) return f; for(int i=1;i<n;i++){ int x[3],y[3],nn=n; int ai=a[i],an=a[n]; set_ST(x,ai); set_ST(y,an); if((!!x[0])+(!!x[1])+(!!x[2])==1)continue; if(y[0]&&y[1]&&y[2]){ nn++; y[0]=y[1]=y[2]=0; } for(int j=0;j<3;j++)if(x[j]){ if((!!x[0])+(!!x[1])+(!!x[2])==2&&(j==1||!x[1]))continue; int t=x[j]; x[j]=0; a[i]=get_ST(x[0],x[1],x[2]); if((!!x[0])+(!!x[1])+(!!x[2])==1||!x[1])a[i]=0;///强力剪枝 x[j]=t; for(int k=0;k<3;k++)if(!y[k]){ y[k]=t; a[nn]=get_ST(y[0],y[1],y[2]); y[k]=0; c[t]=min(c[t],dfs(nn)); } } a[i]=ai; a[n]=an; } if(c[1]==1e9&&c[2]==1e9&&c[3]==1e9){ mat.ins(s,0); return 0.0; } double p=1.0/6.0; if(c[1]==1e9) p+=1.0/3.0,c[1]=0; if(c[2]==1e9) p+=1.0/3.0,c[2]=0; if(c[3]==1e9) p+=1.0/6.0,c[3]=0; f=(c[1]/3.0+c[2]/3.0+c[3]/6.0+1.0)/(1.0-p); mat.ins(s,f); return f; } int main(){ int n; F['G']=1;F['B']=2;F['R']=3; mat.init(); while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++){ scanf("%s",str); a[i]=get_ST(F[str[0]],F[str[1]],F[str[2]]); } printf("%.15lf\n",dfs(n)); } } /** 6 RGB GRG BBB GGR BRG BRB 5 RGB GRG BBB GGR BRG */