一个有意思的博弈

题目描述

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

解题过程

咋一看,这是个明显贪心过程,我们按照两个关键字排序之后对两个人都采用贪心策略模拟就可以了。但是,事实上,这样做是不对的。因为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;
}
好的,我可以为您提供一个简单的博弈树的PyTorch实现,以下是代码: ```python import torch import numpy as np class Node: def __init__(self, state, player): self.state = state self.player = player self.children = [] self.value = None def add_child(self, node): self.children.append(node) def is_leaf(self): return len(self.children) == 0 def is_max(self): return self.player == 1 def is_min(self): return self.player == -1 def minimax(node, alpha, beta): if node.is_leaf(): # evaluate leaf node return node.value if node.is_max(): value = -np.inf for child in node.children: value = max(value, minimax(child, alpha, beta)) alpha = max(alpha, value) if alpha >= beta: break node.value = value return value if node.is_min(): value = np.inf for child in node.children: value = min(value, minimax(child, alpha, beta)) beta = min(beta, value) if alpha >= beta: break node.value = value return value # Example usage # Define initial state initial_state = torch.tensor([0, 0, 0, 0, 0, 0, 0, 0, 0]) # Create root node root = Node(initial_state, 1) # Generate all possible child nodes for i in range(9): if initial_state[i] == 0: new_state = initial_state.clone() new_state[i] = 1 root.add_child(Node(new_state, -1)) # Run minimax algorithm on root node minimax(root, -np.inf, np.inf) # Get optimal child node optimal_child = None optimal_value = -np.inf for child in root.children: if child.value > optimal_value: optimal_value = child.value optimal_child = child # Optimal move is index of changed value in state optimal_move = (initial_state - optimal_child.state).nonzero()[0].item() print("Optimal move:", optimal_move) ``` 这个代码实现了一个具有最小值和最大值节点的博弈树,并使用minimax算法来搜索最佳移动。在这个例子中,我们模拟井字棋游戏,并在根节点上生成所有可能的子节点。然后,我们运行minimax算法来搜索最佳子节点,并返回最佳移动的索引。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值