1. 程式人生 > >【題解】 bzoj1076: [SCOI2008]獎勵關 (裝壓+期望dp)

【題解】 bzoj1076: [SCOI2008]獎勵關 (裝壓+期望dp)

狀態 span 方程 con can i+1 std tin log

題面戳我

Solution

  • 並不會做,看了下題解大概了解了。期望這個東西好難搞啊qwq
  • 我們定義\(dp[i][j]\)表示第\(i\)步,拿到寶物前的狀態為\(j\)
  • 正著來會有很多不合法的情況,剔除比較麻煩,我們反著來考慮,因為你想如何是合法,就是狀態表示拿得物品個數小於等於步數嘛,倒著來最後答案根據我們狀態定義可以知道,答案是\(dp[1][0]\)嘛,然後你想,我們每向前一次,就最多剔除一個寶物,最多剔除的就是\(K\)個,其余不合法的情況到最後不會剔除完,就不會被計入答案中
  • 轉移方程是\[dp[i][j]=dp[i][j]+\Sigma_{k=1}^n max(dp[i+1][j],dp[i+1][j|(sta[k])+s[k]])/n\]
    這個是在\(j\)狀態下能加入\(k\)物品.
  • 不然轉移方程就是\[dp[i][j]=dp[i][j]+dp[i+1][j]/n\]
  • 多做幾道期望dp,感受下吧qwq

Code

//It is coded by ning_mew on 7.21
#include<bits/stdc++.h>
#define db double
using namespace std;

const int maxk=105,maxn=20;

int n,K;
int sta[maxn],s[maxn];
db dp[maxk][(1<<15)+100];

int main(){
  scanf("%d%d",&K,&n);
  for(int i=1;i<=n;i++){
    int box=0;
    scanf("%d",&s[i]);
    while(1){
      scanf("%d",&box);if(!box)break;
      sta[i]=(sta[i]|(1<<(box-1))); 
    }
  }
  for(int i=K;i>=1;i--){
    for(int j=0;j<=(1<<n)-1;j++){
      for(int k=1;k<=n;k++){
        if((sta[k]&j)!=sta[k]){dp[i][j]=dp[i][j]+dp[i+1][j]/n;continue;}
        dp[i][j]=dp[i][j]+1.0*max(dp[i+1][j],dp[i+1][j|(1<<(k-1))]+s[k])/n;
      }
    }
  }printf("%0.6f\n",dp[1][0]);return 0;
}

博主蒟蒻,隨意轉載。但必須附上原文鏈接:http://www.cnblogs.com/Ning-Mew/,否則你會場場比賽暴0!!!

【題解】 bzoj1076: [SCOI2008]獎勵關 (裝壓+期望dp)