HDU 5013 City Tour

题意:m个游客,n座城市(m, n <= 16), 每个人从1走到n, 每次有一定概率停在原地,然后以后就不前进了。一个人到过一个城会得到一定的愉悦度,对于相邻的两座城,会额外产生Cj / Cj - 1 * Hj的愉悦度,Cj是到过j城的人数,Hj是到过j城的人在这里获得的愉悦度之和。求期望的总愉悦度。


解法:首先,城市给人提供的愉悦度可以直接计算出来。设dp[i][j]代表到在i城的人的集合为j的概率,额外提供的愉悦度期望可以在统计dp[i] -> dp[i + 1]的转移时计算出来。考虑dp[i][j] -> dp[i + 1][k]的转移中,必要条件是k是j的子集,然后这个转移发生的概率可以通过j到k的变化计算出来,愉悦度是cnt[k] * sumh[i + 1][k] / cnt[j],sumh[i + 1][k]代表i + 1城中k集合的人的愉悦度之和。因为期望的可加性,这一次转移对答案的贡献就是概率 * 愉悦度。分析愉悦度的式子,发现枚举了i之后,cnt[k] * sumh[i + 1][k]只和k有关,cnt[j]只和j有关。因此统计转移给答案的贡献之前,可以把每个dp[i][j]除以cnt[j]。这个转移是一个类似高维前缀和的过程,顺次枚举把某一维变成0的转移后,两个集合之间的路径是唯一的,因此只需考虑某维从1变成0的转移即可,复杂度为n * n * 2 ^ n.

City Tour

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 198    Accepted Submission(s): 54
Special Judge


Problem Description
There are m visitors coming to visit country A, and they plan to visit all n cities in the country one after another. The cities are numbered from 1 to n by the order they are visited. The visitors start their tour at city 1. Each day, for each visitor i, he has p i probability to go to next city(which means city number increases by 1), and 1 - p iprobability to fall in love with current city and stay there till the end of tour. If a visitor reach city n, he will not move any more.

When visitor i reach city j, he get H ij units of happiness.For j > 1, suppose city j is visited by c j(c j>0) visitors and city j - 1 is visited by c j - 1(c j - 1 > 0) visitors, then each of c j city j's visitors will get extra   units of happiness.

Let h tot denote the total happiness of all visitors at the end of tour. Now you need to calculate the expectation of h tot.
 

Input
There are multiple test cases. Please process till EOF. 

For each case, the first line contains two integers m and n (1 ≤ m ≤ 16,1 ≤ n ≤ 16) , indicating the number of visitors and the number of cities respectively.

The second line contains m real numbers p i(0 ≤ p i ≤ 1)—the probability for the i th visitor to move to next city each day. The probabilities are given with at most 6 digits after decimal point.

Then there are m lines follow, each line contains n integers. The j-th integer of ith line denotes h ij (1 ≤ h ij ≤ 100).
 

Output
For each test case, print a single real number in a line, represents the expectation of h tot. The answer will be considered valid if it differs from the correct one by at most 10 -5.
 

Sample Input
   
   
   
   
3 1 0.1 0.2 0.3 10 20 30 3 3 0.5 0.5 0.5 1 1 1 1 1 1 1 1 1 4 4 0.1 0.4 0.2 0.3 7 2 18 10 2 6 9 5 4 4 19 17 7 3 13 17
 

Sample Output
   
   
   
   
60.0000000 6.84375000 34.230645587
 

Source
2014 ACM/ICPC Asia Regional Xi'an Online
 

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

const int N = 18;

double f[N][N], dp[N][1<<N], sumh[N][1<<N], h[N][N];
int n,m, num[1<<N];
int C(int x)
{
    int c=0;
    for(;x;x>>=1) if(x&1) c++;
    return c;
}
void work()
{
    for(int i=1;i<=m;i++) {
        f[i][1]=1;
        scanf("%lf", &f[i][2]);    ///f[i][2]是第i个人去下一个点的概率
        for(int j=3;j<=n;j++) f[i][j] = f[i][j-1] * f[i][2];    ///f[i][j] 第i个人到点j概率
    }
    double ans=0;
    for(int i=1;i<=m;i++) {
        for(int j=1;j<=n;j++)
            scanf("%lf",&h[i][j]),ans+=h[i][j] * f[i][j];
    }
    int full=1<<m;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<full;j++) {
            dp[i][j]=1;
            sumh[i][j]=0;
            for(int k=1;k<=m;k++)
            if(j&(1<<k-1)) {
                dp[i][j] *= f[k][i];
                sumh[i][j] += h[k][i];
            }
            else
                dp[i][j] *= 1-f[k][i];
        }
    }
    for(int i=1;i<n;i++) {
        for(int k=1;k<full;k++) dp[i][k]/=num[k];
        for(int j=1;j<=m;j++) {
            for(int k=0;k<full;k++) {
                if(k&(1<<j-1)) {
                    dp[i][k-(1<<j-1)] += dp[i][k] * (1 - f[j][2]);
                    dp[i][k] *= f[j][2];
                }
            }
        }
        for(int k=0;k<full;k++) ans+=dp[i][k] * num[k] * sumh[i+1][k];
    }
    printf("%.12f\n", ans);
}

int main()
{
    num[0]=0;
    for(int i=1;i<(1<<16);i++) num[i]=C(i);
    while(cin>>m>>n) work();
    return 0;
}


你可能感兴趣的:(HDU 5013 City Tour)