藍橋杯-對局匹配 | 分組+線性DP

問題描述(題目鏈接:對局匹配
  小明喜歡在一個圍棋網站上找別人在線對弈。這個網站上所有註冊用戶都有一個積分,代表他的圍棋水平。
  小明發現網站的自動對局系統在匹配對手時,只會將積分差恰好是K的兩名用戶匹配在一起。如果兩人分差小於或大於K,系統都不會將他們匹配。
  現在小明知道這個網站總共有N名用戶,以及他們的積分分別是A1, A2, ... AN。
  小明想了解最多可能有多少名用戶同時在線尋找對手,但是系統卻一場對局都匹配不起來(任意兩名用戶積分差不等於K)?
輸入格式
  第一行包含兩個個整數N和K。
  第二行包含N個整數A1, A2, ... AN。
  對於30%的數據,1 <= N <= 10
  對於100%的數據,1 <= N <= 100000, 0 <= Ai <= 100000, 0 <= K <= 100000
輸出格式
  一個整數,代表答案。
樣例輸入
10 0
1 4 2 8 5 7 1 4 2 8
樣例輸出
6


思路 (參考博客:https://blog.csdn.net/flyawayl/article/details/79068946)

  如果把n個元素按照將分數相差爲k的用戶分成一組,例如第一組就是{0,k,2k,3k...},第二組就是{1,k+1,2k+1...},等等。這樣分組的話,每個分組的用戶是不可能和其他分組的用戶匹配成功的,因爲分差不可能爲k

  這樣的話,只要在每個分組裏面選取儘量多的用戶就可以了。用cnt(i)表示分數爲i的用戶人數,假設現在第i組有m個不同分數{x,x+k,x+2k,...,x+(m1)k},其中x表示該組第一個人的積分,那麼用動態規劃法來選擇儘量多的人數。dp(j)表示選擇前j個分數能獲得的最大用戶人數(價值),很明顯如果選擇第j個分數,那麼第j1個分數是不能選的,因爲它們的積分相差k,該組最大在線人數爲dp(m)


  狀態轉移方程如下:

                                                dp[i] = max( dp[i-1] , dp[i-2]+cnt[score] )

  其中cnt(score)表示積分爲第i個分數的總人數。是否感覺上述動態方程與01揹包很類似?
需要注意的是,k=0要特殊處理。

這個題最主要的是解決分組的問題,解決分組之後就能想到用DP的思想求得最大值。

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

const int maxn=1e5+10;
int a[maxn],dp[maxn],cnt[maxn];

int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(a,0,sizeof(a));
        int  x;
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&x);
            a[x]++;
        }

        int ans=0,id;
        if(k==0)
        {
            for(int i=0; i<maxn; ++i)
                if(a[i]) ++ans;
        }
        else
        {
            for(int i=0; i<k; ++i)
            {
                id=0;
                for(int j=i; j<maxn; j+=k)
                    cnt[id++]=a[j];

                dp[0]=cnt[0];
                for(int j=0; j<id; ++j)
                {
                    if(j==1) dp[j]=max(dp[j-1],cnt[j]);
                    else
                    {
                        dp[j]=max(dp[j-1],dp[j-2]+cnt[j]);
                    }
                }
                ans+=dp[id-1];
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章