/**//* 一棵树n<=180,树上每条边的长度都是1,若两点的距离为len,则他们通信的代价就是d[len] d[]是给出的 可以选一些点建立Information Reform,这些点可自动获取信息,建立一个这样的点代价为k 其他没建的点就会与最近的Information Reform通信,以获取信息 求使得树上所有点都能获取信息的最小代价,以及它们各自要通信的Information Reform
不会做.看了解题报告还是一头雾水,知道需要O(n^3)的树形dp 看别人代码的 dp[u,c]表示u的这棵子树,其中u以c为Information Reform的最小代价,但u的子树上的 其他点不一定以c为Information Reform 则dp[u,c] = cost[u,v] + ∑min{dp[v,c], dp[v,center[v]] + k} center[u],它是使u这棵子树所有点获得信息的最小代价的Information Reform
注意的是center[u]是指使u这棵子树所有点能获得信息的最小代价,不一定是最后的答案 所以输出答案时,可以自顶向下,比如0的肯定是center[0],然后利用之前的转移 dp[u,c] = cost[u,v] + ∑min{dp[v,c], dp[v,c'] + k} 去更新子树实际的center[v] if dp[v,center[u]] < dp[v,center[v]] + k center[v] = c
第一次遇到这样的树形dp,在考虑某棵子树时,影响它代价的可以是整棵树(如这里可以以u子树外 的点为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
搜索
最新评论
|
|