poj3046 Ant Counting(动态规划)

poj3064 Ant Counting(动态规划)

题目链接http://poj.org/problem?id=3046

题目大意:有T(1<=T<=1000)种蚂蚁,共有A只,每种最多有Ni(1<=Ni<=100)。不同种类的蚂蚁可以相互区分但相同种类无法区分。从这些蚂蚁中挑取S种,S+1种…B种,共有多少种取法,求出方案数膜1000000的余数。

动态规划策略:设dp[i][j]为前i种蚂蚁取出j只出来的方案数。
则状态转移方程为:dp[i][j] = dp[i-1][j] + dp[i][j-1]
这种取法有点类似于01完全背包,区别只是这个背包有上限,而完全背包无上限。
所以当j>ant[i](第i种蚂蚁的数目)时,dp[i][j]的值还要减去dp[i-1][j-a[i]-1]
意思是要除去从i-1种蚂蚁中取j-a[i]-1只,在从第i种蚂蚁种取a[i]+1只的情况。

动态规划方程:所以最终的动态规划方程如下:

if( j > a[i] ):
    dp[i][j] = (dp[i-1][j] + dp[i][j-1] - dp[i-1][j-a[i]-1] + M) % M;
else:
    dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % M;

注意这里有个+M然后在对M求模,是因为前面做了减法,可能会出现负值,因此先加上一个M然后在求模就能保证结果为正了。

动态规划的初值:对于dp的初值只需要考虑对于每个i当j=0的时候,很容易发现dp[i][0]=1。因为只有一种取法,那就是不取。

下面是已ac的代码:

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

using namespace std;

#define M 1000000

int T, A, S, B;
int a[1010]; // ant family[i] 有a[i]个ant

int dp[1010][10010];// dp[i][j] 前i个取j个的取法总数

int main()
{
        int x;
        scanf( "%d%d%d%d", &T, &A, &S, &B );
        for ( int i = 0 ; i < A ; ++ i ) {
                scanf( "%d", &x );
                a[x]++;
        }
        // 取n个的取法总数
        int res = 0;
        for ( int i = 0 ; i <= T ; ++ i ) dp[i][0] = 1;// 取0个总有一种方法
        for ( int i = 1 ; i <= T ; ++ i ) {
                for ( int j = 1 ; j <= B ; ++ j ) {
                        if ( j > a[i] ) {
                                dp[i][j] = (dp[i-1][j] + dp[i][j-1] - dp[i-1][j-a[i]-1] + M)%M;
                        } else {
                                dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % M;
                        }
                }
        }
        for ( int i = S ; i <= B ; ++ i ) {
                res = (res+dp[T][i]) % M;
        }
        printf( "%d\n", res );

        return 0;
}

猜你喜欢

转载自blog.csdn.net/hopygreat/article/details/79658314
ANT
今日推荐