• 【BZOJ1076】[SCOI2008] 奖励关(状压DP)


    点此看题面

    大致题意: 总共有(n)个宝物和(k)个回合,每个回合系统将随机抛出一个宝物(抛出每个宝物的概率皆为(1/n)),吃掉一个宝物可以获得一定的积分(积分可能为负),而吃掉某个宝物有一定的前提,即先吃掉若干种宝物每个至少一次,才能吃掉该宝物。请你求出在最优策略的情况下的最优得分。

    状压(DP)

    由于这道题的数据范围很小,我们可以考虑状压(DP),状压DP就是用一个数二进制下的每一位来存储一个信息,这里就用来存储某个宝物是否被吃掉过

    我们可以用(f[i][j])记录第(i)个回合,当前状态为(j)时能获得的最大收益。

    如果我们正着DP,那么显然可以发现,当我们要从一个状态转移至另一个状态时,有可能前一个状态无法得到,因此我们要倒着推

    这样,我们就能得出DP转移方程:

    f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(q-1))]+a[q]);
    

    其中,我们要满足当前状态(j)满足吃掉宝物(q)所需的条件,然后枚举每一个符合条件的(j)即可。

    注意,要判断当前状态(j)是否满足条件,有个很简单的方法:判断(j)&(s[q])(s[q])存储吃掉宝物(q)所需的条件,这里也利用了状态压缩)是否等于(s[q]),如果相等,便说明(j)这个状态中包含了(s[q]),即说明当前状态满足吃掉宝物(q)所需的条件。

    状压(DP)

    #include<bits/stdc++.h>
    #define N 15
    #define K 100
    using namespace std;
    int n,k,a[N+5],s[N+5];
    double f[K+5][(1<<N)+5];
    inline char tc()
    {
    	static char ff[100000],*A=ff,*B=ff;
    	return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0;int f=1;char ch;
    	while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
    	while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    	x*=f;
    }
    int main()
    {
    	register int i,j,q;
    	for(read(k),read(n),i=1;i<=n;++i)
    		for(read(a[i]),read(j),s[i]=0;j;read(j))
    			s[i]|=1<<(j-1);//用状态压缩将吃掉宝物所需的条件存储下来
    	for(i=k;i;--i)//倒着进行DP
    		for(j=0;j<(1<<n);++j)
    		{
    			for(q=1;q<=n;++q)
    			{
    				if((j&s[q])==s[q]) f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(q-1))]+a[q]);//判断是否满足条件,更新答案
    				else f[i][j]+=f[i+1][j];
    			}
    			f[i][j]/=n;//由于每种情况的概率是1/n,所以要除以n
    		}
    	return printf("%.6lf",f[1][0]),0;
    }
    
  • 相关阅读:
    Android 颜色配置表-颜色类
    Android模拟器——Genymotion
    Android-adb shell 读取手机系统文件
    android webview js交互 第一节 (java和js交互)
    Android源码目录结构详解(转载)
    BlockingQueue深入分析(转)
    RUDP之三 —— Virtual Connection over UDP
    RUDP之二 —— Sending and Receiving Packets
    OSS层基础:平台区分
    RUDP之一 —— UDP VS TCP
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1076.html
Copyright © 2020-2023  润新知