藍橋杯 試題 歷屆試題 對局匹配 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 <= 100000spa

輸出格式.net

  一個整數,表明答案。設計

樣例輸入code

10 0
1 4 2 8 5 7 1 4 2 8blog

樣例輸出get

6string


 

解題思路:一開始看到是以分差爲K分組匹配,想到的是用並查集將分差等於K的分爲一組,這樣每組之間都不會匹配,再從每組中選擇一個最佳方案,把最優方案相加便可

獲得一個最優解。但如何在並查集同一組中選擇最優方案又成了問題。最後看到別的朋友的思路才知道用DP解決。個人代碼主要和一位朋友的類似,因此附上連接https://blog.csdn.net/Helloirbd/article/details/88070674 個人代碼只是用了《挑戰程序設計競賽》的風格重複了一遍。

能夠用A數組保存積分 k (0<=k<=100000)出現的次數,將積分相差n*K的(0<=n<=Max_N/K) 的分爲一組,這樣就能夠獲得K組 (數值%K=0,1,...,K-1),在每一組中

用dp找到最優方案。dp[ i ]:某一組前 i 個的最優方案(這裏有點難表述)。對於第 i 個有兩種選擇:選擇和 i 位置相差 2*K的對手,這樣第 i 個位置的選手也符合條件; 或者選擇和

位置 i 積分相差K的選手,這是位置 i 的選手不符合條件。體如今代碼中:dp[ i ] = max ( dp[ i -2 ] + cnt[ i ], dp[ i-1 ]  )

實現代碼:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int Max_N = 100000;
 7 const int Max_K = 100000;
 8 //輸入 
 9 int N,K;
10 int A[Max_N+1];//A[i]:數值i出現了多少次
11  
12 void solve()
13 {
14     int sum = 0;
15     if( K==0 )//K==0時單獨考慮 
16     {
17         for(int i=0; i<=Max_K; i++){
18             if( A[i] )    sum++; //相同積分做爲匹配的一組,只能選一人 
19         }
20         printf("%d\n",sum);
21         return;
22     }
23     for(int i=0; i<K; i++)//分爲K組 
24     {
25         int cnt[Max_K/K+1];//積分爲相差n*K的一組 
26         int dp[Max_K/K+1];//dp數組 
27         memset(dp,0,sizeof(dp));//初始化值爲0 
28         
29         int k = 0;
30         for(int j=i; j<=Max_K; j+=K )
31         {
32             cnt[k++] = A[j];//其中一組 
33         }
34         
35         dp[0] = cnt[0];
36         dp[1] = cnt[1];//前兩個單獨考慮 (i-2>=0) 
37         for(int j=2; j<k; j++)
38         {
39             dp[j] = max( dp[j-2]+cnt[j], dp[j-1]);
40         }
41         sum += dp[k-1];
42     }    
43     printf("%d\n",sum);
44 }
45 
46 int main()
47 {
48     scanf("%d%d",&N,&K);
49     while( N-- )
50     {
51         int a;
52         scanf("%d",&a);
53         A[a]++;
54     }
55     
56     solve();
57     
58     return 0;
59 }

/*(註釋):若是有朋友看到的話,但願能夠給個人表述提出本身的意見,或者能夠一塊兒學習進步。

相關文章
相關標籤/搜索