zoukankan      html  css  js  c++  java
  • poj 3046 Ant Counting(多重集组合数)

    Ant Counting

    Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)
    Total Submission(s) : 3   Accepted Submission(s) : 2
    Problem Description
    Bessie was poking around the ant hill one day watching the ants march to and fro while gathering food. She realized that many of the ants were siblings, indistinguishable from one another. She also realized the sometimes only one ant would go for food, sometimes a few, and sometimes all of them. This made for a large number of different sets of ants!

    Being a bit mathematical, Bessie started wondering. Bessie noted that the hive has T (1 <= T <= 1,000) families of ants which she labeled 1..T (A ants altogether). Each family had some number Ni (1 <= Ni <= 100) of ants.

    How many groups of sizes S, S+1, ..., B (1 <= S <= B <= A) can be formed?

    While observing one group, the set of three ant families was seen as {1, 1, 2, 2, 3}, though rarely in that order. The possible sets of marching ants were:

    3 sets with 1 ant: {1} {2} {3}
    5 sets with 2 ants: {1,1} {1,2} {1,3} {2,2} {2,3}
    5 sets with 3 ants: {1,1,2} {1,1,3} {1,2,2} {1,2,3} {2,2,3}
    3 sets with 4 ants: {1,2,2,3} {1,1,2,2} {1,1,2,3}
    1 set with 5 ants: {1,1,2,2,3}

    Your job is to count the number of possible sets of ants given the data above.
     

     

    Input
    * Line 1: 4 space-separated integers: T, A, S, and B <br> <br>* Lines 2..A+1: Each line contains a single integer that is an ant type present in the hive
     

     

    Output
    * Line 1: The number of sets of size S..B (inclusive) that can be created. A set like {1,2} is the same as the set {2,1} and should not be double-counted. Print only the LAST SIX DIGITS of this number, with no leading zeroes or spaces.
     

     

    Sample Input
    3 5 2 3 1 2 2 1 3
     

     

    Sample Output
    10
     

    分析:

    多重集组合数也是由多重背包问题拓展出来的一类经典问题。这里仍然给大家讲2种方法:

    ①朴素方法:

    状态:dp[i][j]:前i种中选j个可以组成的种数

    决策:第i种选k个,k<=ant[i] && j-k>=0

    转移:dp[i][j]=Σdp[i-1][j-k]

    复杂度为O(B*Σant[i])即O(B*A)也即O(A^2),虽说这题A最大可到1e5,但是实际数据水,能过

     

    ②优化递推式

    状态:dp[i][j]:前i种中选j个可以组成的种数

    决策:第i种不选或者至少选一个

    转移:

    1.若不选,显然为dp[i-1][j]

    2.若至少选一种,那么为dp[i][j-1]-dp[i-1][j-ant[i]-1]

    我们这样来理解,dp[i][j-1] 理解为已经选了第i种一个,至于还选不选这里我们不管它,所以它可以用来代表至少选一个

    但是dp[i][j-1]还有一层含义便是前i种中选j-1个可以组成的种数,所以它包含了选ant[i]个第i种,即dp[i-1][j-ant[i]-1],但

    dp[i][j] 最多选ant[i]个第i种,所以最后要减去这一种。

    所以 dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]

    复杂度为O(T*B)

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 using namespace std;
     6 const int mod = 1000000;
     7 int dp[1005][100005];
     8 int main()
     9 {
    10     int ant[1005];
    11     int t, a, s, b;
    12     cin >> t >> a >> s >> b;
    13     memset(ant, 0, sizeof(ant));
    14     int i;
    15     int j;
    16     for (i = 1; i <= a; i++)
    17     {
    18         cin >> j;
    19         ant[j]++;
    20     }
    21     for (i = 0; i <= t; i++) dp[i][0] = 1;
    22     dp[0][0] = dp[1][0] = 1;
    23     for (i = 1; i <= t; i++)
    24     {
    25         for (j = 1; j <= b; j++)
    26         {
    27             if (j - ant[i] - 1 >= 0)
    28             {//在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
    29                 dp[i][j] = (dp[i - 1][j] + dp[i ][j - 1] - dp[i - 1][j - ant[i] - 1] + mod) % mod;
    30             }
    31             else
    32             {
    33                 dp[i][j] = (dp[i - 1][j] + dp[i][j - 1])%mod;
    34             }     
    35         }
    36     }
    37     int sum = 0;
    38     for (i = s; i <= b; i++)
    39         sum = (sum + dp[t][i]) % mod;
    40     cout << sum << endl;
    41     return 0;
    42 }
    View Code

    为了节约空间%2;

    #include<iostream>  
    using namespace std;  
    #define MOD 1000000  
    int T, A, S, B;  
    int ant[1005];  
    int dp[2][100000];  
    int ans;  
    int main()  
    {  
        scanf("%d%d%d%d", &T, &A, &S, &B);  
        for (int i = 1; i <= A; i++)  
        {  
            int aa;  
            scanf("%d", &aa);  
            ant[aa]++;  
        }  
        dp[0][0] = dp[1][0] = 1;  
        for (int i = 1; i <= T; i++)  
            for (int j = 1; j <= B; j++)  
                if (j - ant[i] - 1 >= 0) dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1] - dp[(i - 1) % 2][j - ant[i] - 1] + MOD) % MOD;      //在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)  
                else dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1]) % MOD;  
        for (int i = S; i <= B; i++)  
            ans = (ans + dp[T % 2][i]) % MOD;  
        printf("%d
    ", ans);  
        return 0;  
    }  
    View Code
     
  • 相关阅读:
    WEBSERVICE 分析器错误信息: 未能创建类型
    Powerdesigner中表导出sql语句关于字段注释乱码的问题
    配置redis服务器允许远程连接
    [转]ubuntu系统重新分区、根目录扩容
    [转]自动驾驶平台Apollo 2.5环境搭建
    [转]在ROS下使用zeroconf配置多机通信
    ROS 安装完成后运行小乌龟示例程序
    [转]RoboWare Studio的使用和发布器/订阅器的编写与测试
    【转】ROS之topic和service通信比较
    【转】贝叶斯公式的直观理解(先验概率/后验概率)
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/8435173.html
Copyright © 2011-2022 走看看