历届试题:对局匹配

问题描述

  小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。


  小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是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

题目分析:

首先在输入这n个分数的同时,用数组 book[ ] 和map来统计每个分数出现的次数。

当k=0时情况比较特殊。

例如样例1中:

n=10,k=0,对于分数1 4 2 8 5 7 1 4 2 8 求分数差 不为0 的最多人数是:1,2,4,8,5,7即每个分数只匹配一位。这样只需要求map的大小就可以了。

当k!=0时:需要用到动态规划来做。

例如: k=2,对于分数1 4 2 8 5 7 1 4 2 8,我们将其分为K组,每一组相邻两个分数差为K,即-------第一组:分数段:0 2 4 6 8

                          次数段arr[ ]={ 0 ,2 ,2 ,0 ,2 }(每个分数出现的次数)

            第二组:分数段:  1 3 5 7 9

                          次数段:2 0 1 1 0

这样我们在进行选择时,保证不选择相邻的次数就好了,而选择相邻次数中的哪一个就需要用到动规来做:

这里我先总结一下动态规划转移方程,很容易看懂:

dp[i]=arr[i]                          i==0

dp[i]=max(dp[i-1],arr[i])               i==1

dp[i]=max(dp[i-1],dp[i-2]+arr[i])        i>1

这样第一组动规后的结果为:dp[ ]={0,2,2,2,4}  dp[i]就表示前i个人能取得的最多人数

第二组动规后的结果为:dp[ ]={2,2,3,3,3}

取得每一组动规结果的最后一个数相加就是我们要的结果了,这里就是4+3=7;

#include<iostream>
#include<map>
using namespace std;
int book[100005],a[100005],dp[100005];
map<int,int> mp;
int main()
{
    int i,j,n,k,t,x=0,ans=0;
    cin>>n>>k;
    for (i=0;i<n;i++)
    {
        cin>>t;
        book[t]++;
        mp[t]++;
    }
    if (k==0)
    {
       cout<<mp.size()<<endl;
        return 0;
    }
    else
    {
        for (i=0;i<k;i++)
        {
            x=0;
            for (j=i;j<100005;j+=k)
           		 a[x++]=book[j];
            for (j=0;j<x;j++)
            {
                if (j==0)
	                dp[0]=a[0];
                else if (j==1)
    	            dp[1]=max(a[1],dp[0]);
                else
        	        dp[j]=max(dp[j-1],dp[j-2]+a[j]);
            }
            ans+=dp[x-1];
        }
    }
    cout<<ans;
    return 0;
}

 

 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值