P2016 戰略遊戲
阿新 • • 發佈:2018-12-27
一道還算比較好寫的“求樹的最大獨立集”的問題。
f [ x ] [ 0 ] 表示以x為節點的子樹上,在x位置不放士兵時,士兵數量的最小值;
f [ x ] [ 1 ] 表示以x為節點的子樹上,在x位置要放士兵時,士兵數量的最小值;
那麼方程就寫出來了,在回溯的時候,對於f [ x ] [ 0 ] ,它的子節點一定都要放,累加f [ x ] [ 1 ] ;那麼對於f [ x ] [ 1 ] ,取最小值就可以了。
注意邊界判斷,當你到樹的葉子的時候,要在操作 f 之後返回。
程式碼如下:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; #define maxn 2000 struct data { int num,child[maxn]; } node[maxn]; int f[maxn][3],n,root; bool vis[maxn]; void dp(int x) { f[x][0]=0; f[x][1]=1; if(!node[x].num) return ; for(int i=1;i<=node[x].num;i++) { dp(node[x].child[i]); f[x][0]+=f[node[x].child[i]][1]; f[x][1]+=min(f[node[x].child[i]][1],f[node[x].child[i]][0]); } } int main() { memset(f,0x3f,sizeof(f)); scanf("%d",&n); for(int i=1;i<=n;i++) { int x,y; scanf("%d",&x); scanf("%d",&node[x].num); for(intj=1;j<=node[x].num;j++) { scanf("%d",&node[x].child[j]); vis[j]=1; } } while(vis[root]) root++; dp(root); printf("%d",min(f[root][0],f[root][1])); return 0; }
最後想加一句,所謂樹形dp,我認為就是想方設法利用剛剛到過(並從那裡回來)的點更新現在這個點,更新到最後就是答案了。