您的位置:首页 > 其它

POJ 3046---Ant Counting(多重组合数)

2017-11-26 22:25 344 查看

                                                       
POJ 3046---Ant Counting

                http://poj.org/problem?id=3046
多重组合数问题原型:

有n种物品,第i种物品有a[i]个。不同种类可以取分但相同种类物品无法区分,从这些物品中取出m个的话,有多少种取法。

题意理解:

有T种蚂蚁,问这些蚂蚁分别取出 S.S+1...B 个的话,有多少种取法,就是原型中有若干个不同的m。

dp[i][j]:从前i种物品中取出j个的组合总种类数。

递推关系:从前i-1种取出j-k个,第i种取出k个。

dp[i][j]=∑dp[i-1][j-k](k从0到min(j,a[i])

一般这种连加符号或者max(完全背包不就是?)都根据递推定义,分离一项进行化简。

①:当j<=a[i]:

dp[i][j]=∑dp[i-1][j-k](k从0到j:j,j-1...1,0)

        =dp[i-1][j]+∑dp[i-1][j-k](k从1到j:j-1..0)

       
=dp[i-1][j]+∑dp[i-1][j-1-(k-1)]

       
=dp[i-1][j]+dp[i][j-1]

②:当a[i]<j:

dp[i][j]=∑dp[i-1][j-k](k从0到a[i]:j,j-1...j-a[i])

=dp[i-1][j]+∑dp[i-1][j-k](k从1到a[i]:j-1...j-a[i])

=dp[i-1][j]+∑dp[i-1][j-1-(k-1)]
 (凑dp[i][j-1],先+再-)

=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1-a[i]]

初始化:dp[i][0]=1(一个都不取的方法总是只有1种)

注意:不能用一维数组,原因:当前位置的状态取决于上,左上,和左。左上要逆序,左要顺序,矛盾!所以只能滚动数组了。

AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define M (int)1e6
int dp[2][100*1000+5];
int ant[1005];

int main()
{
int T, A, S, B;
cin >> T >> A >> S >> B;
for (int i = 1; i <= A; i++)
{   int x; scanf("%d", &x);
ant[x]++;
}
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])
dp[i % 2][j] = (dp[i % 2][j - 1] + dp[(i-1) % 2][j] - dp[(i-1) % 2][j - 1 - ant[i]] + M) % M;
else dp[i % 2][j] = (dp[i % 2][j - 1] + dp[(i - 1) % 2][j]) % M;
}
int ans=0;
for (int i = S; i <= B; i++)
ans = (ans + dp[T % 2][i]) % M;

cout << ans<<endl;
system("pause");

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: