1. 程式人生 > 實用技巧 >【賈志豪NOIP模擬題】慰問員工 cheer 【最小生成樹】【對邊權值的一些處理】

【賈志豪NOIP模擬題】慰問員工 cheer 【最小生成樹】【對邊權值的一些處理】

Description

  LongDD 變得非常懶, 他不想再繼續維護供員工之間供通行的道路. 道路被用來連線 N(5 <= N <= 10,000)個房子, 房子被連續地編號為 1..N. 每一個房子都是一個員工的家. LongDD 計劃除去 P(N-1 <= P <= 100,000)條道路中儘可能多的道路, 但 是還要保持房子之間的連通性. 你首先要決定那些道路是需要保留的 N-1 條道路.

  第 j 條雙向道路連線了房子 S_j 和 E_j (1 <= S_j <= N; 1 <= E_j <= N; S_j != E_j), 而且走完它需要 L_j (0 <= L_j <= 1,000)的時間.沒有兩個房子是被一條以上的道 路所連線.


  員工們非常傷心, 因為她們的交通系統被削減了. 你需要到每一個員工的住處去安 慰她們. 每次你到達第 i 個房子的時候(即使你已經到過), 你必須花去 C_i (1 <= C_i <= 1,000)的時間和員工交談.

  你需要從某一個房子出發(這是供你選擇的),並最終回到這個房子。期間,你要經 過每個房子至少一次,並且當你經過某個房子的時候,你必須和這個房子裡的員工 交談(即使你已經到過).

  假設 LongDD 採納了你的建議, 請計算出使所有員工都被安慰的最少時間.

Input

* 第 1 行: 用空格隔開的兩個整數 N 和 P
* 第 2..N+1 行: 第 i+1 行包含了一個整數: C_i

* 第 N+2..N+P+1 行: 第 N+j+1 行包含用空格隔開的三個整數: S_j, E_j 和 L_j

Output

* 第 1 行: 一個整數, 所需要的總時間(包含和在你所在的房子的員工的兩次談話 時間).

Sample Input

5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
4 5 12

Sample Output

176

如果不考慮對每家每戶的訪問時間 也不考慮要往返的時間
則這題是一個最小生成樹模板題
接下來考慮影響
我們對每條邊的權值變成兩倍再加上其兩端點訪問距離
再求最小生成樹
貼程式碼
#include<cstdio>
#include
<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m; struct edge { int u,v,l; }a[100010]; int f[10010],c[10010]; int cmp(const void *a,const void *b) { return (((edge*)a)->l < ((edge*)b)->l ? -1 : 1); } void read() { scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%d",&c[i]),f[i]=i; for (int i=0; i<m; i++) { scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].l); a[i].l<<=1; a[i].l+=c[a[i].v]+c[a[i].u]; } qsort(a,m,sizeof(a[0]),cmp); } int find(int x) { if (x == f[x]) return f[x]; return (f[x]=find(f[x])); } void together(int u,int v) { int x=find(u),y=find(v); f[x]=f[y]; } void kruscal() { int ans=0x7ffffff,x=0; for (int i=1; i<=n; i++) f[i]=i,ans=min(ans,c[i]); for (int i=0; i<m; i++) { if (find(a[i].u) == find(a[i].v)) continue; together(a[i].u,a[i].v); ans+=a[i].l; x++; if (x == n-1) break; } printf("%d\n",ans); } int main() { read(); kruscal(); return 0; }
View Code