 /**//*
一棵樹n<=180,樹上每條邊的長度都是1,若兩點(diǎn)的距離為len,則他們通信的代價(jià)就是d[len]
d[]是給出的
可以選一些點(diǎn)建立Information Reform,這些點(diǎn)可自動(dòng)獲取信息,建立一個(gè)這樣的點(diǎn)代價(jià)為k
其他沒建的點(diǎn)就會(huì)與最近的Information Reform通信,以獲取信息
求使得樹上所有點(diǎn)都能獲取信息的最小代價(jià),以及它們各自要通信的Information Reform

不會(huì)做 .看了解題報(bào)告還是一頭霧水,知道需要O(n^3)的樹形dp
看別人代碼的
dp[u,c]表示u的這棵子樹,其中u以c為Information Reform的最小代價(jià),但u的子樹上的
其他點(diǎn)不一定以c為Information Reform
則dp[u,c] = cost[u,v] + ∑min{dp[v,c], dp[v,center[v]] + k}
center[u],它是使u這棵子樹所有點(diǎn)獲得信息的最小代價(jià)的Information Reform

注意的是center[u]是指使u這棵子樹所有點(diǎn)能獲得信息的最小代價(jià),不一定是最后的答案
所以輸出答案時(shí),可以自頂向下,比如0的肯定是center[0],然后利用之前的轉(zhuǎn)移
dp[u,c] = cost[u,v] + ∑min{dp[v,c], dp[v,c'] + k}
去更新子樹實(shí)際的center[v]
if dp[v,center[u]] < dp[v,center[v]] + k
center[v] = c

第一次遇到這樣的樹形dp,在考慮某棵子樹時(shí),影響它代價(jià)的可以是整棵樹(如這里可以以u(píng)子樹外
的點(diǎn)為Information Reform) ------------------OMG
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>
#include<numeric>
#include<cassert>
#include<ctime>
#include<bitset>

using namespace std;

const int MAXN = 200;
const int INF = 0x3f3f3f3f;

vector<int> e[MAXN];
int w[MAXN][MAXN], d[MAXN];
int center[MAXN], dp[MAXN][MAXN];
int n, k;

 void floyd() {
 for (int k = 0 ; k < n; k++) {
 for (int i = 0; i < n ; i ++) {
 if(w[i][k] == INF) {
continue;
}
 for (int j = 0 ; j < n; j++) {
 if(w[k][j] == INF) {
continue;
}
w[i][j] = min(w[i][j], w[i][k] + w[k][j]);
}
}
}
}

 void dfs(int u, int p) {
 for (vector<int>::iterator it = e[u].begin() ; it != e[u].end(); it++) {
int v = *it;
 if(v != p) {
dfs(v, u);
}
}
center[u] = 0;
 for (int f = 0; f < n ; f ++) {
dp[u][f] = d[w[u][f]];
 for (vector<int>::iterator it = e[u].begin(); it != e[u].end(); it++) {
int v = *it;
 if(v != p) {
dp[u][f] += min(dp[v][f], dp[v][center[v]] + k);
}
}
 if(dp[u][f] < dp[u][center[u]]) {
center[u] = f;
}
}
}

 void retrieve(int u, int p) {
 for (vector<int>::iterator it = e[u].begin() ; it != e[u].end(); it++) {
int v = *it;
 if(v != p) {
int f = center[u];
 if(dp[v][f] < dp[v][center[v]] + k) {
center[v] = f;
}
retrieve(v, u);
}
}
}

int main()
  {
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
 for (; ~scanf("%d%d", &n, &k); ) {
fill(w[0], w[n], INF);
 for (int i = 0 ; i < n ; i ++ ) {
e[i].clear();
w[i][i] = 0;
}
 for (int i = 1 ; i < n ; i ++) {
scanf("%d", &d[i]);
}
 for (int i = 1,u,v; i <n; i++) {
scanf("%d%d", &u, &v);
u--;
v--;
e[u].push_back(v);
e[v].push_back(u);
w[u][v] = w[v][u] = 1;
}
floyd();
dfs(0,0);
retrieve(0,0);
printf("%d\n", dp[0][center[0]] + k);//還要加上k
 for (int i = 0 ; i < n ; i ++) {
 if (i >0) {
putchar(' ');
}
printf("%d", center[i] + 1);
}
puts("");
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評(píng)論

|
|