1. 程式人生 > >bzoj2563 阿貍和桃子的遊戲

bzoj2563 阿貍和桃子的遊戲

公平性 sta problem medium ring UC ios 正在 思考

傳送門

題目

阿貍和桃子正在玩一個遊戲,遊戲是在一個帶權圖G=(V, E)上進行的,設節點權值為w(v),邊權為c(e)。遊戲規則是這樣的:
  1. 阿貍和桃子輪流將圖中的頂點染色,阿貍會將頂點染成紅色,桃子會將頂點染成粉色。已經被染過色的點不能再染了,而且每一輪都必須給一個且僅一個頂點染色。
  2. 為了保證公平性,節點的個數N為偶數。

  3. 經過N/2輪遊戲之後,兩人都得到了一個頂點集合。對於頂點集合S,得分計算方式為技術分享圖片
  由於阿貍石頭剪子布輸給了桃子,所以桃子先染色。兩人都想要使自己的分數比對方多,且多得越多越好。如果兩人都是采用最優策略的,求最終桃子的分數減去阿貍的分數。

Input

 輸入第一行包含兩個正整數NM,分別表示圖G的節點數和邊數,保證N一定是偶數。
 接下來N+M行。
 前N行,每行一個整數w,其中第k行為節點k的權值。
 後M行,每行三個用空格隔開的整數a b c,表示一條連接節點a和節點b的邊,權值為c

Output

 輸出僅包含一個整數,為桃子的得分減去阿貍的得分。

Sample Input

4 4
6
4
-1
-2
1 2 1
2 3 6
3 4 3
1 4 5

Sample Output

3
對於100%的數據,1 ≤ N ≤ 10000,1 ≤ M ≤ 100000,-10000 ≤ w , c ≤ 10000。

分析

貪心神仙題,設桃子所取節點染色為0,阿貍為1,則對於一條邊的兩個點有一下3中情況:

1. 0 0

2. 0 1 / 1 0

3. 1 1

對於這三種情況,設點權為v1和v3,邊權為v2,則桃子所得的差值增加量分別為:

1. v1+v2+v3

2. ±(v1-v3)

3. -(v1+v2+v3)

到這裏,經過感性的思考後,我們不難發現如果因為目的是使所取差值最大,所以當我們設v1‘=v1+v2/2,v2‘=0,v3‘=v3+v2/2時,3種取點情況所產生的差值增加量不變,而最優策略即為取新點權最大的點。

但我們還有兩個要註意的點:

1.因為點權可能為奇數,為防止精度問題,我們將所有新點權值乘2,即:v1‘=2*v1+v2,v3‘=2*v3+v2

2.因為最後輸出值為桃子所得值-阿貍所得值,所有我們在取點是需要記錄一下這個點是誰取的,在最後進行處理並判斷他是否得到邊權

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
using namespace std;
int d[110000];
struct node{
int pl,v;
}a[110000];
struct edge{
int x,y,z;
}e[110000];
bool cmp(const node &x,const node &y){
return x.v>y.v;
}
map<int,int>is;
int main(){
int n,m,i,j,k,x,y,z;
cin>>n>>m;
for(i=1;i<=n;i++){
cin>>x;
d[i]=x;
a[i].v=2*x;
a[i].pl=i;
}
for(i=1;i<=m;i++){
cin>>x>>y>>z;
e[i].x=x;
e[i].y=y;
e[i].z=z;
a[x].v+=z;
a[y].v+=z;
}
sort(a+1,a+n+1,cmp);
int ans1=0,ans2=0;
for(i=1;i<=n;i++)
if(i%2){
ans1+=d[a[i].pl];
is[a[i].pl]=1;
}else {
ans2+=d[a[i].pl];
}
for(i=1;i<=m;i++)
if(is[e[i].x]==is[e[i].y]){
if(is[e[i].x])ans1+=e[i].z;
else ans2+=e[i].z;
}
cout<<ans1-ans2<<endl;
return 0;
}

bzoj2563 阿貍和桃子的遊戲