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