• SCOI2008 奖励关


    传送门

    这题状态和转移都很好想,但是问题在于转移顺序。
    一开始我是自然的考虑正推的……考虑到会出现一些不合法的情况,我使用bool数组来记录当前状态是否可用。但是这样出现的问题在于,因为最终要计算平均答案,很多种选择情况 它的终止集合是不同的,而答案也不是把他们简单的加起来……

    于是我们考虑倒推……倒推就不会存在有状态不合法的情况了。用(dp[i][S])表示第1轮到第i−1轮内宝物是否取过的状态为S,第i轮到第k轮的最大期望得分。
    这样的话转移方程就是:(dp[i][S] += max(dp[i+1][S],dp[i+1][S | (1<<(q-1))] + v[q]) / n)(dp[i][S] += dp[i+1][S] / n) 前者是可以转移,后者是不能。

    答案显然是(dp[1][0]).

    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 10000005;
     
    int read()
    {
       int ans = 0,op = 1;char ch = getchar();
       while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
       while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
       return ans * op;
    }
    
    int k,n,S[20],num,x;
    double dp[105][1<<16],p,v[20],ans;
    
    int main()
    {
       k = read(),n = read(),p = (double)(n);
       rep(i,1,n)
       {
          scanf("%lf",&v[i]);
          x = read();
          while(x) S[i] |= (1<<(x-1)),x = read();
       }
       per(i,k,1)
       {
          rep(j,0,(1<<n)-1)
          {
    	 rep(q,1,n)
    	 {
    	    if((S[q] & j) == S[q])
    	    dp[i][j] += max(dp[i+1][j],dp[i+1][j | (1<<(q-1))] + v[q]) / p;
    	    else dp[i][j] += dp[i+1][j] / p;
    	 } 
          }
       }
       printf("%.6lf
    ",dp[1][0]);
       return 0;
    }
    
    
  • 相关阅读:
    matlab后处理保存avi动画
    Python3在Windows安装配置及简单试用
    Matlab,C++存取二进制
    批量修改文件名
    这是我的第一篇博客园博客
    android的平台架构及特性
    Android开发学习
    跟着9张思维导图学习Javascript
    如何使用css和jquery控制文章标题字数?
    分离构造器(2-2)
  • 原文地址:https://www.cnblogs.com/captain1/p/10544421.html
Copyright © 2020-2023  润新知