1. 程式人生 > 實用技巧 >洛谷P4643 [國家集訓隊]阿狸和桃子的遊戲 & 初賽心情

洛谷P4643 [國家集訓隊]阿狸和桃子的遊戲 & 初賽心情

洛谷P4643 [國家集訓隊]阿狸和桃子的遊戲

引入

其實是道小水題,沒有那麼多的資料結構和卡常。但是我就是喜歡這種題!giao!

(希望這道題不要變色啊……這可是我a的第一道黑題啊啊啊……

蒟蒻的心情激動不已啊

原題傳送門

題目描述

阿狸和桃子正在玩一個遊戲,遊戲是在一個帶權圖G=(V, E)上進行的,設節點權值為w(v),邊權為c(e)。遊戲規則是這樣的:

  1. 阿狸和桃子輪流將圖中的頂點染色,阿狸會將頂點染成紅色,桃子會將頂點染成粉色。已經被染過色的點不能再染了,而且每一輪都必須給一個且僅一個頂點染色。

  2. 為了保證公平性,節點的個數N為偶數。

  3. 經過N/2輪遊戲之後,兩人都得到了一個頂點集合。對於頂點集合S,得分計算方式為

\sum_{v \in S}w(v) + \sum_{e=(u,v)\in E \land u,v\in S}c(e)vSw(v)+e=(u,v)Eu,vSc(e)

由於阿狸石頭剪子布輸給了桃子,所以桃子先染色。兩人都想要使自己的分數比對方多,且多得越多越好。如果兩人都是採用最優策略的,求最終桃子的分數減去阿狸的分數。

輸入格式

輸入第一行包含兩個正整數N和M,分別表示圖G的節點數和邊數,保證N一定是偶數。

接下來N+M行。

前N行,每行一個整數w,其中第k行為節點k的權值。

後M行,每行三個用空格隔開的整數a b c,表示一條連線節點a和節點b的邊,權值為c。

輸出格式

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

輸入輸出樣例

輸入 #1
4 4
6
4
-1
-2
1 2 1
2 3 6
3 4 3
1 4 5
輸出 #1
3

說明/提示

資料規模和約定

對於40%的資料,1 ≤ N ≤ 16。

對於100%的資料,1 ≤ N ≤ 10000,1 ≤ M ≤ 100000,-10000 ≤ w , c ≤ 10000。


Solution

先理解那個式子——

兩個人依次選點

而最終的得分等於

選的點數的和

再加上其選的每兩點之間的直接的邊之和

即:一條邊僅當它所連線的兩個點都被同一個人所選,這條邊的w才歸這個人所有。

邊和點都對答案有所影響,怎麼辦呢?要是隻有點權就好了啊!

欸……那能不能把邊權轉化為點權呢?可以的!把邊權對半分給邊就好了!

我們從一張圖中扣下來一條邊,仔細分析一下:

如圖,A和B是點(權),C是邊(權)。

如果直接使用上面的性質我們可以分類討論一下:

下面分4中情況

  1. 桃子把A和B都染成了粉色,那麼桃子得到了這ABC的權ans=(A+C/2)+(B+C/2)=A+B+C;
  2. 桃子把A染成了粉色,阿狸把B染成了紅色,那麼得分為(A+C/2)-(B+C/2)=A-B;
  3. 桃子把B染成了粉色,阿狸把B染成了紅色,那麼得分為(B+C/2)-(A+C/2)=B-A;
  4. 阿狸把A和B都染成了紅色,那麼得分為-(A+C/2)-(B+C/2)=-(A+B+C);

發現這和暴力加是一樣的!

所以,只要把邊權平分到兩個點上再進行排序,奇數偶數分配即可!

Code

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #define IL inline
11 #define re register
12 #define LL long long
13 #define ULL unsigned long long
14 #define re register
15 using namespace std;
16 
17 template<class T>inline void read(T&x)
18 
19 {
20     char ch=getchar();
21     while(!isdigit(ch))ch=getchar();
22     x=ch-'0';ch=getchar();
23     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
24 }
25 inline int read()
26 {
27     int x=0;
28     char ch=getchar();
29     while(!isdigit(ch))ch=getchar();
30     x=ch-'0';ch=getchar();
31     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
32     return x;
33 }
34 int G[55];
35 template<class T>inline void write(T x)
36 {
37     int g=0;
38     do{G[++g]=x%10;x/=10;}while(x);
39     for(re int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
40 }
41 int n,m;
42 double ans,a[10010];
43 bool cmp(const double & a,const double & b){
44     return a>b;
45 }
46 int main()
47 {
48     cin>>n>>m;
49     for(int i=1;i<=n;i++) cin>>a[i];
50     for(int i=1,x,y;i<=m;i++)
51     {
52         double z;
53         cin>>x>>y>>z;
54         a[x]+=z/2;
55         a[y]+=z/2;
56     }
57     sort(a+1,a+n+1,cmp);
58     for(int i=1;i<=n;i++) if(i&1) ans+=a[i];else ans-=a[i];
59     cout<<ans;
60     return 0;
61 }

小結

心情不錯,今天上午考完了初賽,估分77.5……希望能進複賽,當然,要是AFO的話……那就AFO吧……就當作是場錯付吧……

(要是不會真的 “考完初賽回來A了一道黑題,結果發現今年AFO了”吧?)呸呸呸,烏鴉嘴

OVER