[置顶] codeforces 424E Colored Jenga (状态压缩,概率dp用hash记忆优化搜索)

题意:

给出以最多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
*/



你可能感兴趣的:([置顶] codeforces 424E Colored Jenga (状态压缩,概率dp用hash记忆优化搜索))