BZOJ[2563] 阿狸和桃子的游戏

这个题的正解和之前做过的网络流的文理分科差不多,都是一个把对两个点都有贡献的边的贡献分别加给两个点;

在这个题里,首先考虑阿狸拿走了所有的边权与点权,那么现在桃子的分数为0,阿狸的分数为所有权值的加和,那么考虑桃子选每一个点所造成的贡献,每当桃子选了一个点v,则桃子的分数加上w[v],阿狸的分数减去w[v],于此同时,阿狸失去了所有以v为一个端点的边的权值,所以选v时,桃子将差距缩小了2*w[v]+∑以v为一个端点的边的权值,由于每次只加了一次边权,所以当选了一个边的两端点时,贡献就算了2次,刚好符合游戏规则(两次是同点一样,桃子+w,阿狸-w,所以是2*w); 

先求出阿狸的sum,然后每一个点的权值就是2*w[v]+∑以v为一个端点的边的权值,然后sort排序,从大到小选N/2个,要注意因为是轮流选,所以桃子只能隔着选,

Code

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 # define maxn 10010
 8 # define max_m 100010
 9 using namespace std;
10 typedef long long LL;
11 int n,m;
12 LL val[maxn];
13 struct node{
14     int u,v,nxt; LL w;
15 }g[2*max_m];
16 int adj[maxn],e;
17 void add(int u,int v,LL w){
18     g[e].u=u; g[e].v=v; g[e].w=w; g[e].nxt=adj[u];
19     adj[u]=e++;
20 }
21 LL sum;
22 void init(){
23     scanf("%d%d",&n,&m);
24     for(int i=1;i<=n;i++) scanf("%lld",&val[i]),sum+=val[i];
25     memset(adj,-1,sizeof(adj));
26     int x,y; LL z;
27     for(int i=1;i<=m;i++){
28         scanf("%d%d%lld",&x,&y,&z);
29         add(x,y,z); add(y,x,z);
30         sum+=z;
31     }
32     sum=-sum;
33 }
34 bool cmp(const int a,const int b){return a>b;}
35 void work(){
36     for(int i=1;i<=n;i++){
37         val[i]*=2;
38         for(int j=adj[i];j!=-1;j=g[j].nxt){
39             int v=g[j].v;
40             val[i]+=g[j].w;
41         }
42     }
43     sort(val+1,val+n+1,cmp);
44     for(int i=1;i<=n;i+=2){
45         sum+=val[i];
46     }
47     cout<<sum<<endl;
48 }
49 int main(){
50     // freopen("a.in","r",stdin);
51     init();
52     work();
53 }
View Code
原文地址:https://www.cnblogs.com/FOXYY/p/7653050.html