[2016-3-28 Test]

来源:互联网 发布:步惊云软件网址 编辑:程序博客网 时间:2024/05/15 04:37
/*小Z 的袜子DescriptionZYB 很喜欢袜子,他决定送一些袜子给机房里的人。机房里有n 个人,但是他们脚的尺码可能不一样,一共有m 种尺码,第i 个人的尺码为j 的概率为aij(ai1+...+aim=1)。ZYB会带来n双袜子,并逐个询问机房里的人,如果他的尺码的袜子还有,ZYB就会送给他一双,否则将他跳过。ZYB想知道他带n 双袜子来最多期望送出几双。读入格式第一行读入两个数n和m,接下来n行每行读入m 个整数表示aij*1000。输出格式输出一个数表示答案。Sol:先不考虑一个人要带多少种什么样的袜子考虑不同种的袜子。如果给定n个人,带某种袜子,他期望送出的袜子是和别的种类的袜子无关而又由于期望的线性性质,E(X) = p1*E(x1)+p2*E(x2)+....+pn*E(xn)我们只要dp出n个人,第k种袜子,带j双期望能送出多少双。dp[i][j][k]表示前i个人,带j双尺码为k的袜子,期望能送出多少双g[i][j], n个人,带i双尺码为j的袜子,期望能送出多少双那么g[i][j]=dp[n][i][j]现在考虑不同种的袜子装包f[i][j], 前i种袜子,共带j双袜子,期望能送出多少双f[i][j] = max(f[i-1][k]+g[j-k][i])就可以O(n^3)解决了*/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define maxn 3010using namespace std;int n, m;double p[maxn][maxn/10];double dp[110][110][110], g[110][110], f[110][110];int main(){    //freopen("gift.in", "r", stdin);freopen("gift.out", "w", stdout);    scanf("%d%d", &n, &m);    int x;    for(int i = 1; i <= n; i ++){        for(int j = 1; j <= m; j ++){            scanf("%d", &x);            p[i][j] = x / 1000.0;        }    }    //前i个人,带j双尺码为k的袜子,期望能送出多少双    for(int k = 1; k <= m; k ++)        for(int i = 1; i <= n; i ++)            for(int j = 1; j <= i; j ++)                dp[i][j][k] = (dp[i-1][j-1][k] + 1) * p[i][k] + dp[i-1][j][k] * (1 - p[i][k]);    //g[i][j], n个人,带i双尺码为j的袜子,期望能送出多少双    for(int i = 1; i <= n; i ++)        for(int j = 1; j <= m; j ++)            g[i][j] = dp[n][i][j];    //f[i][j],前i种袜子,共带j双袜子,期望能送出多少双    //f[i][j] = max(f[i-1][k]+g[j-k][i])    for(int i = 1; i <= m; i ++)        for(int j = 0; j <= n; j ++)            for(int k = 0; k <= j; k ++)                f[i][j] = max(f[i][j], f[i-1][k] + g[j-k][i]);    printf("%.12f\n", f[m][n]);    return 0;}
/*对选择的每一双袜子统计贡献。显然选择同一种袜子多次,贡献会越来越小。于是先通过计算g[n][1][i]来计算每种袜子选第一双的贡献。然后每次选择贡献最大的进行更新。更新时通过计算g[n][now+1][i]得出再选一双这种袜子的贡献,然后加入堆中。总共只会计算n+m次贡献。效率:n(n+m)logm 期望得分100*/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#define maxn 3010using namespace std;int n, m;struct Pair{    int x; double y;    Pair(int x = 0, double y = 0):x(x), y(y){}    bool operator<(const Pair& k)const{        if(y != k.y)return y < k.y;        return x < k.x;    }};priority_queue<Pair> Q;int tot, dl1[maxn * 3], dl2[maxn * 3], fr[maxn * 3];double p[maxn][maxn/10], a[maxn * 3][maxn], b[maxn * 3];double ans;inline void cal(){    int x = dl1[tot];    for(int i = 1; i <= n; i ++)        a[tot][i] = a[tot][i-1]*(1-p[i][x])+a[fr[tot]][i-1]*p[i][x];    //a[tot][i]表示前i个人不选这双袜子的概率    b[tot] = b[fr[tot]] + a[tot][n];    //选现在的不选以前的+选以前的不选现在的。}int main(){    freopen("gift.in", "r", stdin); freopen("gift.out", "w", stdout);    scanf("%d%d", &n, &m);    int x;    for(int i = 1; i <= n; i ++){        for(int j = 1; j <= m; j ++){            scanf("%d", &x);            p[i][j] = x / 1000.0;        }    }    for(int i = 1; i <= m; i ++){        dl1[i] = i, dl2[i] = 1, a[i][0] = 1;        tot ++; cal();        Q.push(Pair(i, 1 - b[i]));//1-b[i]表示前j只全都送出去的概率    }    for(int i = 1; i <= n; i ++){        Pair P = Q.top(); Q.pop();        ans += P.y; tot ++; fr[tot] = P.x;        dl1[tot] = dl1[P.x], dl2[tot] = dl2[P.x] + 1;        cal(), P.x = tot, P.y = 1 - b[tot], Q.push(P);    }    printf("%.12lf\n", ans);    return 0;}
0 0