bzoj1076 [SCOI2008]奖励关

bzoj1076 [SCOI2008]奖励关


特别水的一道dp。
n<=15那肯定状压
枚举出现的宝物,判断选或不选
复杂度\(O(n^{2}\times2^n\times k)\)

mdzz可恶的latex..

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "2473"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define db long double
typedef long long ll;
il int gi(){
    rg int x=0;rg bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
db f[101][1<<15];
int p[16],lim,n,m;
bool e[16][16];//e[i][j]表示有j才能捡i
//f[i][j] i~n关 1~i-1宝物情况为j i~n的最大得分期望
int main(){
#ifdef xzz
    freopen(Fname".in","r",stdin);
    freopen(Fname".out","w",stdout);
#endif
    n=gi(),m=gi(),lim=(1<<m)-1;
    rep(i,1,m){
        p[i]=gi();
        static int ls;while(ls=gi(),ls)e[i][ls]=1;
    }
    db eps=1.00/m,ls;
    bool flg;
    rep(i,0,lim)f[n+1][i]=0;
    drep(i,n,1)rep(j,0,lim){
        f[i][j]=0;
        rep(k,1,m){//第i轮丢的宝物为k
            ls=f[i+1][j];//不捡
            flg=1;
            rep(l,1,m)if(e[k][l]&&(j&(1<<l-1))==0){flg=0;break;}
            if(flg)ls=max(ls,f[i+1][j|(1<<k-1)]+p[k]);
            f[i][j]+=ls*eps;
        }
    }
    printf("%.6Lf\n",f[1][0]);
    return 0;
}

一个较强的优化:预处理出某个状态时是否能放,省去每次判断的过程
复杂度\(O(n\times k\times2^n)\)

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "2473"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define db long double
typedef long long ll;
il int gi(){
    rg int x=0;rg bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
db f[101][1<<15];
int p[16],lim,n,m;
bool e[16][16];
bool yes[1<<15][16];
int main(){
#ifdef xzz
    freopen(Fname".in","r",stdin);
    freopen(Fname".out","w",stdout);
#endif
    n=gi(),m=gi(),lim=(1<<m)-1;
    rep(i,1,m){
        p[i]=gi();
        static int ls;while(ls=gi(),ls)e[i][ls]=1;
    }
    rep(i,0,lim)rep(j,1,m){
        yes[i][j]=1;
        rep(k,1,m)if(e[j][k]&&(i&(1<<k-1))==0){yes[i][j]=0;break;}
    }
    rg db ls;
    drep(i,n,1)rep(j,0,lim){
        f[i][j]=0;
        rep(k,1,m){
            ls=f[i+1][j];
            if(yes[j][k])ls=max(ls,f[i+1][j|(1<<k-1)]+p[k]);
            f[i][j]+=ls;
        }f[i][j]/=m;
    }
    printf("%.6Lf\n",f[1][0]);
    return 0;
}

更神奇的玄学优化:位运算改用数组初始化(OTZ IOT)

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "2473"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define db double
typedef long long ll;
il int gi(){
    rg int x=0;rg bool flg=0;rg char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
const int w[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
db f[101][1<<15];
int p[16],lim,n,m;
bool e[16][16];
bool yes[1<<15][16];
int main(){
#ifdef xzz
    freopen(Fname".in","r",stdin);
    freopen(Fname".out","w",stdout);
#endif
    n=gi(),m=gi(),lim=(1<<m)-1;
    rep(i,1,m){
        p[i]=gi();
        static int ls;while(ls=gi(),ls)e[i][ls]=1;
    }
    rep(i,0,lim)rep(j,1,m){
        yes[i][j]=1;
        rep(k,1,m)if(e[j][k]&&(i&w[k-1])==0){yes[i][j]=0;break;}
    }
    rg db ls;
    drep(i,n,1)rep(j,0,lim){
        f[i][j]=0;
        rep(k,1,m){
            ls=f[i+1][j];
            if(yes[j][k])ls=max(ls,f[i+1][j|w[k-1]]+p[k]);
            f[i][j]+=ls;
        }f[i][j]/=m;
    }
    printf("%.6lf\n",f[1][0]);
    return 0;
}
posted @ 2017-10-06 11:19  菜狗xzz  阅读(156)  评论(0编辑  收藏  举报