题目描述
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状,某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
思路:
做过最大独立集,最小点覆盖,这次终于写到了最小支配集。
最小支配集是选择最少的点去覆盖所有的点,每个选择的点可以覆盖相连的点和它本身。
dp方程:
1.f[pos][0]=min(f[v][0],f[v][2]);
2.f[pos][1]+=min(f[v][0],f[v][2]);
3.f[pos][2]+=min(f[v][0],min(f[v][1],f[v][2]));
1. 可以监控T的子树 不放本身结点
2. 可以不监控T的子树 不放本身结点
3. 可以监控T的子树 放本身结点
所以说第一种情况需要讨论,如果存在f[v][2]被选,就不需要管,因为可以保证pos被v覆盖.
如果没有f[v][2]被选,就需要在abs(f[v][0]-f[v][2])中选一个最小值,
来选.
还有这道题的输入不能搞错....
代码:
#include<bits/stdc++.h> #define ll long long #define R register using namespace std; const int N=1e5+85; struct E{ int nxt,to; }e[N]; int n,num,head[N],rot[N],val[N],root=1,f[N][3]; inline void add(R int u,R int v){ e[++num].to=v; e[num].nxt=head[u]; head[u]=num; } // 监控T的子树 不放0 // 可以不监控 不放1 // 监控T的子树 放 2 inline void dp(R int pos,R int fa){ f[pos][2]=val[pos]; R int pd=1,vis=1,cha=0x3f3f3f3f; for(R int i=head[pos];i;i=e[i].nxt){ R int v=e[i].to; if(v!=fa){ pd=0; dp(v,pos); if(f[v][0]>=f[v][2]){ f[pos][0]+=f[v][2]; vis=0; } else{ f[pos][0]+=f[v][0]; cha=min(cha,f[v][2]-f[v][0]); } f[pos][1]+=min(f[v][0],f[v][2]); f[pos][2]+=min(f[v][0],min(f[v][1],f[v][2])); } } if(vis&&pd==0) f[pos][0]+=cha; if(pd){ f[pos][0]=val[pos]; f[pos][1]=0; f[pos][2]=val[pos]; } } int main(){ scanf("%d",&n); for(R int i=1;i<=n;++i){ R int p,m,w; scanf("%d%d%d",&p,&w,&m); val[p]=w; for(R int j=1;j<=m;++j){ R int k; scanf("%d",&k); add(k,p);add(p,k); rot[k]=1; } } while(rot[root])root++; dp(root,0); printf("%d",min(f[root][0],f[root][2])); return 0; }