好题啊
给定边权树 求隔离所有指定点的最小花费
考虑树dp的话 自然想到
f[x]表示子树内处理完从根节点出发没有敌人的最小花费
g[x]表示子树内处理完从根节点出发仍有敌人的最小花费 这个时候仍然合法()
又显然根节点是否有敌人是有影响的 所以分类讨论
首先子树没有敌人不用考虑
I. 根节点有敌人的话 f[x]就是inf
g[x]直接取f[v]和g[v]+cst[i]最小值
表示是否切x->v这条边
II. 如果根节点没有
那么g[x]维护的就是选择一个花费最小的儿子切
而这样的花费就是切掉其他所有儿子的花费加上这个的g[v]
所以我们回溯更新f[]和g[]之前先处理出子树是否有敌人和切掉所有儿子的花费
方程看代码吧 强烈建议自己手推
注意这题开longlong!!!(我的30min啊..)
还有就是不要忘了初值还有读入有0啥的
Time cost : 75min
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 #include<vector> 7 #define itn int 8 #define ms(a,b) memset(a,b,sizeof a) 9 #define rep(i,a,n) for(int i = a;i <= n;i++) 10 #define per(i,n,a) for(int i = n;i >= a;i--) 11 #define inf 1e13 12 using namespace std; 13 typedef long long ll; 14 #define int ll 15 ll read() { 16 ll as = 0,fu = 1; 17 char c = getchar(); 18 while(c < ‘0‘ || c > ‘9‘) { 19 if(c == ‘-‘) fu = -1; 20 c = getchar(); 21 } 22 while(c >= ‘0‘ && c <= ‘9‘) { 23 as = as * 10 + c - ‘0‘; 24 c = getchar(); 25 } 26 return as * fu; 27 } 28 //head 29 const int N = 100003; 30 int head[N],nxt[N<<1],mo[N<<1],cnt; 31 ll cst[N<<1]; 32 void _add(int x,int y,ll w) { 33 mo[++cnt] = y; 34 cst[cnt] = w; 35 nxt[cnt] = head[x]; 36 head[x] = cnt; 37 } 38 void add(int x,int y,ll w) {if(x^y)_add(x,y,w),_add(y,x,w);} 39 40 ll w[N]; 41 ll f[N],g[N]; 42 43 bool col[N],vis[N]; 44 void dfs(int x,int p) { 45 f[x] = g[x] = 0ll,vis[x] = col[x]; 46 ll tot = 0ll; 47 for(int i = head[x];i;i = nxt[i]) { 48 int sn = mo[i]; 49 if(sn == p) continue; 50 dfs(sn,x),vis[x] |= vis[sn]; 51 tot += min(f[sn],g[sn] + cst[i]); 52 } 53 54 if(col[x]) { 55 f[x] = inf; 56 for(int i = head[x];i;i = nxt[i]) { 57 int sn = mo[i]; 58 if(sn == p || !vis[sn]) continue; 59 if(col[sn]) g[x] += g[sn] + cst[i]; 60 else g[x] += min(f[sn],g[sn] + cst[i]); 61 } 62 63 } else { 64 g[x] = tot; 65 for(int i = head[x];i;i = nxt[i]) { 66 int sn = mo[i]; 67 if(sn == p || !vis[sn]) continue; 68 g[x] = min(g[x], tot - min(f[sn],g[sn] + cst[i]) + g[sn]); 69 if(col[sn]) f[x] += g[sn] + cst[i]; 70 else f[x] += min(f[sn],g[sn] + cst[i]); 71 } 72 } 73 } 74 75 signed main() { 76 int n = read(),k = read(); 77 rep(i,1,k) col[read()+1] = 1; 78 rep(i,2,n) { 79 int x = read() + 1,y = read() + 1; 80 add(x,y,read()); 81 } 82 dfs(1,1); 83 printf("%lld\n",min(f[1],g[1])); 84 return 0; 85 }
To be continued 这题还有生成树的O(nlgn)?
虽然复杂度不优秀但是应该好想啊
再看看
原文地址:https://www.cnblogs.com/yuyanjiaB/p/9902552.html
时间: 2024-10-09 04:16:05