POJ 2279 Mr. Young's Picture Permutations(dp)

题目链接

题目大意

  有N个学生合影,站成左对齐的k排,每行分别有N1,N2…NK个人,第一排站最后,第k排站之前。学生身高依次是1…N。在合影时候要求每一排从左到右递减,每一列从后面到前也递减,一共有多少总方案。

解题思路

  考虑放最低的学生的情况,我们会发现,对于所有情况,最低的学生只能放在某一行以及某一列的最后一个位置。假如这个学生不放在行末以及列末,因为他是最低的学生,那么他所在的行和列肯定不会单调。所以说,我们可以根据前面的一个状态来推出后面的一个状态,这个问题可以用dp来求解。
  因为每一排的人数是非递增的。所以对于当前的状态,如果上一行人数和这一行人数不同放在行末肯定也是处于列末的,那么这一行末尾可以放人;如果相同,则只能在最后一行末尾放人。状态转移方程太长了直接看代码吧。。。

代码1

  因为k最多为5,所以要开一个5维数组,但是直接开满\(30^5\)会mle。可以考虑一下,如果只在第一排放人,那么第一维最大30;如果在前两排放人,那么第二维最大15;。。。所以只要开一个31161187的数组就够了。

int n, s[5]; ll dp[31][16][11][8][7];
int main() {
    while(~scanf("%d",&n) && n) {
        zero(s); zero(dp);
        for (int i = 0; i<n; ++i) scanf("%d", &s[i]);
        dp[0][0][0][0][0] = 1;
        for (int a = 0; a<=s[0]; ++a)
            for (int b = 0; b<=s[1]&&b<=a; ++b) 
                for (int c = 0; c<=s[2]&&c<=b; ++c)
                    for (int d = 0; d<=s[3]&&d<=c; ++d)
                        for (int e = 0; e<=s[4]&&e<=d; ++e) {
                            ll &t = dp[a][b][c][d][e];
                            if (a>b) t += dp[a-1][b][c][d][e];
                            if (b>c) t += dp[a][b-1][c][d][e];
                            if (c>d) t += dp[a][b][c-1][d][e];
                            if (d>e) t += dp[a][b][c][d-1][e];
                            if (e) t += dp[a][b][c][d][e-1];
                        }
        printf("%lld\n", dp[s[0]][s[1]][s[2]][s[3]][s[4]]);
    }
    return 0;
}

代码2

  如果不嫌麻烦。。。也可以动态开内存。。。

int n, s[5];
int main() {
    while(~scanf("%d",&n) && n) {
        zero(s);
        for (int i = 0; i<n; ++i) scanf("%d", &s[i]);
        ll *****dp = new ll**** [s[0]+1];
        for (int a = 0; a<s[0]+1; ++a) {
            dp[a] = new ll*** [s[1]+1]; 
            for (int b = 0; b<s[1]+1; ++b) {
                dp[a][b] = new ll** [s[2]+1];
                for (int c = 0; c<s[2]+1; ++c) {
                    dp[a][b][c] = new ll* [s[3]+1];
                    for (int d = 0; d<s[3]+1; ++d)
                        dp[a][b][c][d] = new ll [s[4]+1];
                }
            }
        }
        for (int a = 0; a<=s[0]; ++a)
            for (int b = 0; b<=s[1]; ++b)
                for (int c = 0; c<=s[2]; ++c)
                    for (int d = 0; d<=s[3]; ++d)
                        for (int e = 0; e<=s[4]; ++e)
                            dp[a][b][c][d][e] = 0;
        dp[0][0][0][0][0] = 1;
        for (int a = 0; a<=s[0]; ++a)
            for (int b = 0; b<=s[1]&&b<=a; ++b) 
                for (int c = 0; c<=s[2]&&c<=b; ++c)
                    for (int d = 0; d<=s[3]&&d<=c; ++d)
                        for (int e = 0; e<=s[4]&&e<=d; ++e) {
                            ll &t = dp[a][b][c][d][e];
                            if (a>b) t += dp[a-1][b][c][d][e];
                            if (b>c) t += dp[a][b-1][c][d][e];
                            if (c>d) t += dp[a][b][c-1][d][e];
                            if (d>e) t += dp[a][b][c][d-1][e];
                            if (e) t += dp[a][b][c][d][e-1];
                        }
        printf("%lld\n", dp[s[0]][s[1]][s[2]][s[3]][s[4]]);
        for (int a = 0; a<s[0]+1; ++a) { 
            for (int b = 0; b<s[1]+1; ++b) {
                for (int c = 0; c<s[2]+1; ++c) {
                    for (int d = 0; d<s[3]+1; ++d) {
                        delete dp[a][b][c][d];
                    }
                    delete dp[a][b][c];
                }
                delete dp[a][b];
            }
            delete dp[a];
        }
        delete dp;
    }
    return 0;
}
posted @ 2020-05-22 22:45  shuitiangong  阅读(185)  评论(0编辑  收藏  举报