bzoj 2563: 阿狸和桃子的游戏 贪心

本文介绍了一种基于图的游戏算法,通过将点权和边权重新分配,使得问题转化为简单的贪心选择问题。最终实现了一个高效的算法来解决两人轮流行走以最大化各自得分的问题。

题意

有一个n个点m条边的图,点有点权,边有边权。现在两个人轮流操作,每次每个人可以选择其中一个还未被选择的点。等到两个人都无法操作后,每个人就都得到了一个点集。定义一个点集的贡献为每个点的权值和加上两个端点都属于该点集的边的权值和。现在先手要让两个人权值的差值尽量大,后手要让差值尽量小,问最终结果是多少。
n10000,m100000n≤10000,m≤100000

分析

考虑先手对某个点的决策会对答案造成怎样的贡献:
若选择某个点,则贡献为w,否则贡献为-w。
对于某条边
若两个端点都被选,则贡献为c
若恰好有一个端点被选,则贡献为0
否则贡献为-c
不难发现,如果我们让两个端点的权值均为c/2,那么每一种决策的点权和都会恰好等于其贡献。
接下来只要把点权排序,然后从大到小贪心即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

const int N=10005;

int n,m,w[N];

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]),w[i]*=2;
    for (int i=1;i<=m;i++)
    {
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        w[x]+=z;w[y]+=z;
    }
    std::sort(w+1,w+n+1);
    int ans=0;
    for (int i=1;i<=n;i++)
        if (i&1) ans-=w[i];
        else ans+=w[i];
    printf("%d",ans/2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值