一个有意思的博弈

本文探讨了一种两人轮流取物品的游戏策略问题。通过分析不同玩家的取物逻辑,提出了一种基于双关键字排序的方法,并利用动态规划求解最优策略。最终通过C++代码实现了算法并给出了解决方案。

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

题目描述

有两个人玩游戏,轮流取物品。每个物品对不同的人都会存在不同的价值。对手使用的贪心原则,也就是说在每一步对手都会选择对他价格最大的物品。当存在多个物品价格相同的时候,对手会随机选择一个物品。这个时候问我们可以最多得到多大的结果。

解题过程

咋一看,这是个明显贪心过程,我们按照两个关键字排序之后对两个人都采用贪心策略模拟就可以了。但是,事实上,这样做是不对的。因为A要取的物品也可能是对B很重要的物品,而B正在取的物品则对A没有那么重要,推迟一些取也是可以的。那么,到底怎么做呢?
我做出了一个比较强的结论:在使用了两个关键字排序之后,对于任意的i<n,我们都知道在前i个物品中A至少会取得i/2个物品。
证明:
1. 前i个物品至少需要i/2轮才可以取完。
这个完全不需要证明,每轮两个人各取1个物品,最快取完需要i/2轮
2.我们按照A的逻辑顺序排序,所以A总是会取价值最大的元素,也就是标号较小的元素,即在前i/2轮,A一定不会取标号大于i的物品。
我们证明了这样的定理。
那么也就是说,在前i个物品中,我们最多取i/2个。
这样,就可以得到下面的转移方程:

dp[i][j]=max(dp[i1][j],dp[i1][j1]+Brr[i]),forj<i/2

迭代,就可以得到解

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;

#define LL long long
#define MAXN 1005
#define pi pair<LL,LL>

LL dp[MAXN][MAXN];
int t,n;
pair<LL,LL>P[MAXN];

bool comp(pi a,pi b)
{
    if(a.first==b.first)return a.second>b.second;
    else return a.first>b.first;
}

int main()
{
    freopen("input","r",stdin);
    int i,j;

    scanf("%d",&t);

    while(t--){
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));

        for(i=1;i<=n;i++){
            scanf("%lld",&P[i].first);
        }

        for(i=1;i<=n;i++){
            scanf("%lld",&P[i].second);
        }

        sort(P+1,P+n+1,comp);

        for(i=1;i<=n;i++){
            for(j=1;j<=i/2;j++)
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]+P[i].second);
        }

        printf("%lld\n",dp[n][n/2]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值