P2458 [SDOI2006]保安站崗
阿新 • • 發佈:2022-03-23
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]\)
對於一式,顯然的,自己選不由子節點的狀態決策,只需取 \(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; }