SOS:10分求指错

P2700 逐个击破

## 代码 ```cpp #include <cstdio> #include <algorithm> using namespace std; const int nma=100005; int n,m; int fa[nma],so[nma],bo[nma],fdis[nma]; bool en[nma]; int cod[nma],cos[nma]; int i,j,x,y,z; void link(int x,int y,int z){ if(fa[y]) link(y,fa[y],fdis[y]); fa[y]=x; fdis[y]=z; return; } void calculate(int p){ for(int ion=so[p];ion;ion=bo[ion]){ calculate(ion); } if(en[p]){ cod[p]=fdis[p]; for(int ion=so[p];ion;ion=bo[ion]){ cos[p]+=cod[ion]+cos[ion]; } } else{ int dma=0; for(int ion=so[p];ion;ion=bo[ion]){ cod[p]+=cod[ion]; cos[p]+=cos[ion]+cod[ion]; if(dma<cod[ion]) dma=cod[ion]; } cos[p]-=dma; if(cod[p]>fdis[p]) cod[p]=fdis[p]; } return; } int main() { scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%d",&x); if(!x) x=n; en[x]=1; } for(i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); if(!x) x=n; if(!y) y=n; link(x,y,z); } for(i=1;i<=n;i++){ bo[i]=so[fa[i]]; so[fa[i]]=i; } for(i=1;fa[i];i++) ; calculate(i); printf("%lld",cos[i]); return 0; } ```
by qjyzLfy @ 2020-01-30 15:38:47


## 思路 树形DP。 **1,** 转化成任意有根树。 **2,** 从下往上,计算每个子树的: 1.使该子树上所有有敌军的点都与主树脱离,需要的最小代价( _拆除代价_ ); 2.使该子树内部有敌军的点相互分离,需要的最小代价( _解构代价_ )。 **3,** 输出根节点的解构代价。
by qjyzLfy @ 2020-01-30 15:47:27


## 变量的含义 ``` fa[p] p的父亲. so[p] p的一个儿子 bo[p] p的一个兄弟 (用邻接表存树) fdis[p] p到它父亲的距离 en[p] p点是否有敌军 cod[p] p的拆除代价 cos[p] p的解构代价 dma 子树中cod的最大值 ```
by qjyzLfy @ 2020-01-30 15:54:08


## 转移方程 **如果 p 点有敌军:** `cod[p]=fdis[p]` 因为p必须与主树脱离. `cos[p]`为 p 所有子节点拆除代价与解构代价之和. **如果 p 点没有敌军:** `cod[p]`为 p 所有子节点拆除代价之和 或 `fdis[p]`(取较小者); `cos[p]`为 p 所有子节点拆除代价与解构代价之和,但拆除代价最大的子节点的拆除代价除外.因为有只有一颗子树与 p 相连依然满足 p 被解构.
by qjyzLfy @ 2020-01-30 16:04:55


~~我写得都比题解还详细了,~~ 就帮我看看吧!
by qjyzLfy @ 2020-01-30 16:06:44


0回复惨案,还好我自己找到了...... ``` 6 5 0 1 2 4 5 1 2 10 2 3 1000 3 4 10 3 5 10 3 0 10 ``` 正解 40 ; 输出 60 (拆除代价与解构代价有交集)
by qjyzLfy @ 2020-01-30 23:22:49


|