Hdu 6188 Duizi and Shunzi【思维+Dp】

本文探讨了一种牌类游戏中的算法优化策略,旨在通过合理的组合方式最大化顺子和对子的数量。采用动态规划方法,结合贪心策略实现最优解。

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

Duizi and Shunzi

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 357    Accepted Submission(s): 179


Problem Description
Nike likes playing cards and makes a problem of it.

Now give you n integers, ai(1in)

We define two identical numbers (eg: 2,2) a Duizi,
and three consecutive positive integers (eg: 2,3,4) a Shunzi.

Now you want to use these integers to form Shunzi and Duizi as many as possible.

Let s be the total number of the Shunzi and the Duizi you formed.

Try to calculate max(s).

Each number can be used only once.
 

Input
The input contains several test cases.

For each test case, the first line contains one integer n(1n106). 
Then the next line contains n space-separated integers ai (1ain)
 

Output
For each test case, output the answer in a line.
 

Sample Input
7 1 2 3 4 5 6 7 9 1 1 1 2 2 2 3 3 3 6 2 2 3 3 3 3 6 1 2 3 3 4 5
 

Sample Output
2 4 3 2
Hint
Case 1(1,2,3)(4,5,6) Case 2(1,2,3)(1,1)(2,2)(3,3) Case 3(2,2)(3,3)(3,3) Case 4(1,2,3)(3,4,5)

题目大意:


给出N张牌,连续的三个数字的三张牌可以组成顺子,相同的两个数字组成对子。

问我们最多可以组成多少顺子和对子。


思路:


赛后百度了一波题解,发现大家都会贪心啊TAT:


①首先我们通过简单分析可以得到结论,如果三个连续的数字如果出现了多次。(222333444),我们一定是要先将其选对子,然后去选顺子。那么直接按照对子先选的顺序去贪心可以吗?显然是不行的,比如1 2 3 3 4 5这种,最优解是2,先选对子答案是1.


②那么如果满足上述条件的话,我们不难分析出,如果我们先将这些连续的出现多次的数先取了对子之后,每个数字作为一个顺子的部分的机会是很少的。我们通过简单分析得知,出现了4次就相当多了,反而多出现的顺子部分肯定要作为对子,所以4次肯定是一个可取的极限高度。


③那么我们设定Dp【i】【j】,表示我们以数字i结尾,并且以数字i结尾出现的顺子个数为j个的最优解。这里j最大取4~5其实就足够了。


那么其状态转移我们分成两种情况去走,一种是有重叠部分的去转移,一种是没有重叠部分去转移:




过程维护一下最优解即可,即ans=max(dp【i】【j】);


时间复杂度O(n*4*4)


Ac代码:

#include <bits/stdc++.h>
typedef long long int LL;
int dp[1050000][5];
int have[1050000];
int max(int x,int y)
{
    if(x>y)return x;
    else return y;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        memset(have,0,sizeof(have));
        for(int i=1;i<=n;i++)
        {
            int x;scanf("%d",&x);
            have[x]++;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=4;j++)
            {
                for(int k=0;k<=4;k++)
                {
                    if(j==0)
                    dp[i][j]=max(dp[i][j],dp[i-1][k]+have[i]/2);
                    else
                    {
                        if(i-3>=0&&have[i]>=j&&have[i-1]>=j&&have[i-2]>=j)
                        {
                            dp[i][j]=max(dp[i][j],dp[i-3][k]+j+(have[i]-j)/2+(have[i-1]-j)/2+(have[i-2]-j)/2);
                        }
                        if(i-5>=0&&have[i]>=j&&have[i-1]>=j&&have[i-2]-k>=j)
                        {
                            dp[i][j]=max(dp[i][j],dp[i-2][k]+j-(have[i-2]-k)/2+(have[i]-j)/2+(have[i-1]-j)/2+(have[i-2]-j-k)/2);
                        }
                    }
                }
                ans=max(ans,dp[i][j]);
            }
        }
        printf("%d\n",ans);
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值