P2458 [SDOI2006]保安站岗
P2458 [SDOI2006]保安站岗&& #10157. 「一本通 5.2 例 5」皇宫看守
眼熟吗?UVA1292 Strategic game,#10156. 「一本通 5.2 例 4」战略游戏,最大独立集问题,感觉是不是一模一样?只不过是把边权转到点上了,做法一样,你设 \(f[u][0]\) 为不选,\(f[u][1]\) 为选,则……不细说,于是你获得了\(20\) 分 的好成绩。
其实仔细一想还真不一样,UVA和Loj10156 两题要求覆盖路径,而这两题是覆盖点, 那就决定了前者只用考虑两种决策,因为一条边只可能被两端的点覆盖;后者则可能被自己、儿子、父亲覆盖。
于是设:\(f[u][0]\) 为被自己覆盖,\(f[u][1]\) 为被父亲覆盖,\(f[u][2]\) 为被儿子覆盖,则:
\[f[u][0]= \displaystyle \sum_{v \in son[u]} min(min(f[v][0],f[v][1]),f[v][2])
\]
\[f[u][1]= \displaystyle \sum_{v \in son[u]} min(f[v][0],f[v][2])
\]
\[f[u][2]=min(f[v][0]-f[v][2])(v\in son[u])+ \displaystyle \sum_{v \in son[u]} min(f[v][0],f[v][2])
\]
对于一式,显然的,自己选不由子节点的状态决策,只需取 \(min\) 即可。
对于二式,既然被父亲覆盖了,则节点的状态只能由子节点选或者子节点被子节点的子节点选的 \(min\) 来更新。
对于三式,难理解,意思就是:如果节点被子节点覆盖了,那子节点要么自己覆盖,要么被子节点的子节点覆盖,但是有一个特殊情况,就是必须在子节点中选一个最小的 \(f[v][0]\) 选上,因为如果子节点都是由 \(f[v][2]\) 转移而来的,那么 \(u\) 的子节点就意味着一个也不选,自己就没人覆盖,所以判断这种情况并且要挑一个最小的换上。
/*
Knowledge : Rubbish Algorithm
Work by :Gym_nastics
Time : O(AC)
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
const int N=1e6+6;
int read() {
int x=0,f=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15);
return f?-x:x;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+48);
}
int fa[N],val[N],f[N][3],n,m;
int head[N],cnt;struct node{int v,nxt;}e[N];
void Add_edge(int u,int v){e[++cnt]=(node){v,head[u]};head[u]=cnt;}
void dfs(int u){
f[u][0]=val[u];int Min=INF;bool flg=false;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v;dfs(v);
f[u][0]+=min(f[v][2],min(f[v][0],f[v][1]));
f[u][1]+=min(f[v][0],f[v][2]);
if(f[v][0]<f[v][2]){
f[u][2]+=f[v][0];flg=true;
} else{
Min=min(Min,f[v][0]-f[v][2]);
f[u][2]+=f[v][2];
}
}
if(!flg) f[u][2]+=Min;
}
signed main() {
n=read();int root=1;
for(int i=1;i<=n;i++){
int u=read(),k=read(),m=read();val[u]=k;
for(int j=1;j<=m;j++){
int v=read();Add_edge(u,v);
fa[v]=u;
}
}while(fa[root])root=fa[root];dfs(root);
print(min(f[root][0],f[root][2]));
return 0;
}