poj-1285 Combinations, Once Again(DP)

该博客详细介绍了POJ-1285题目的解题思路,这是一个关于计算给定序列中不同组合数量的问题。通过动态规划(DP)的方法,博主解释了如何计算从特定位置开始,选择特定数量元素的不同组合,并提供了C++代码实现。需要注意的是,重复数字的组合只计算一次。代码中包含了输入输出处理、动态规划状态转移方程以及避免排序和删除重复元素的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

Combinations, Once Again
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1551 Accepted: 522

Description

Given n objects you'd have to tell how many different groups can be chosen if r objects are taken at a time.

Input

Input consists of less than 100 test cases. Each test case begins with two integers n (0 < n <= 50), m (0 <= m <= n). The next line will contain the labels (numbers in the range 1 to n) of the n objects you are to choose from. Two objects with the same label are considered equivalent. Then in the last line for that test case, you'd have m values for r. There will be a single space separating two consecutive numbers in a line. Input is terminated by a test case where n=0, you must not process this test case.

Output

For each test case, print the test case number. And for each query number r, print the number of different groups that can be formed if r objects are taken from the given n objects. You can assume that for all input cases, the output will always fit in a 64-bit unsigned integer and (0<=r<=n).

Sample Input

5 2
1 2 3 4 5
2 1

4 1
1 2 3 4 
2

0 0

Sample Output

Case 1:
10
5
Case 2:
6

题意:给一串序列,求一共有多少不同组合。比如样例1,当r=2的时候,有(1,2)(1,3)(1,4)(1,5)(2,3)(2,4)(2,5)(3,4)(3,5)(4,5)一共十种组合。注意当出现重复数字的时候,如果一个组合两个数字都一样,只算一个。比如序列1,1,2 当r=2时有两个解,一个是(1,1),一个是(1,2)

思路:用dp[i][j]表示从i开始(包括i)r=j时的组合数量。  易知dp[i][j]=dp[i+1][j-1]+dp[k][j]  k为从i开始第一个不等于i的数(因为dp[k][j]代表不取i,那么[i,k)这个区间内的数都一样,如果取了,就矛盾了。)  注意本题不能把数组排序后删去重复的,因为题目可能询问的很大,那么答案是11112223的可能性很大,去掉将很难处理。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int  a[55];
unsigned long long dp[55][55];
int main()
{
    int n,m,r;
    int q=1;
    while(scanf("%d %d",&n,&m)&&(n&&m))
    {
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=n; i++)
            dp[i][0]=1;
        dp[n][1]=1;
        int k;
        for(int i=n-1; i>=1; i--)
        {
            for(int j=1; j<=n; j++)
            {
                dp[i][j]=dp[i+1][j-1];
                for(k=i+1;k<=n;k++)
                    if(a[k]!=a[i])
                        break;
                dp[i][j]+=dp[k][j];
            }
        }
        printf("Case %d:\n",q++);
        while(m--)
        {
            scanf("%d",&r);
                printf("%llu\n",dp[1][r]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值