树形dp
dp[N][2]:
//dp针对当前节点 选或者不选
//dp[i][0];//不选
//dp[i][1];//选
状态转移方程(是关键):
for(int i=0;i<v[root].size();i++) { dp[root][0]+=dp[v[root][i]][1];//若当前节点不选,则子节点必须选 dp[root][1]+=min(dp[v[root][i]][1],dp[v[root][i]][0]);//当前节点选,子节点(选/不选) }
1 //给出n个节点 节点编号0~n-1 2 //每个节点站一个哨兵,每个哨兵观察到与自己相邻的两条边 3 //问最少需要多少个哨兵才能观察到所有边 4 5 #include<string.h> 6 #include<iostream> 7 #include<stdio.h> 8 #include<algorithm> 9 #include<queue> 10 #include<vector> 11 #include<map> 12 #include<cmath> 13 using namespace std; 14 #define inf 0x3f3f3f3f 15 #define inff 0x3f3f3f3f3f3f3f3f 16 const int N=1550; 17 #define mod 998244353 18 typedef long long ll; 19 20 int n; 21 vector<int>v[N]; 22 int f[N],dp[N][2]; 23 //dp针对当前节点 选或者不选 24 //dp[i][0];//不选 25 //dp[i][1];//选 26 void dfs(int root) 27 { 28 dp[root][0]=0;//当前根节点不选 29 dp[root][1]=1;//当前根节点选 30 for(int i=0;i<v[root].size();i++) 31 dfs(v[root][i]); 32 for(int i=0;i<v[root].size();i++) 33 { 34 dp[root][0]+=dp[v[root][i]][1];//若当前节点不选,则子节点必须选 35 dp[root][1]+=min(dp[v[root][i]][1],dp[v[root][i]][0]);//当前节点选,子节点(选/不选) 36 } 37 } 38 39 int main() 40 { 41 while(~scanf("%d",&n)) 42 { 43 memset(f,-1,sizeof(f));//因为节点编号0~n-1 44 for(int i=1;i<=n;i++) 45 { 46 int root,node,son; 47 scanf("%d:(%d)",&root,&node); 48 v[root].clear();//记得清空 49 for(int j=1;j<=node;j++) 50 { 51 scanf("%d",&son); 52 v[root].push_back(son);//单向边 53 f[son]=root; 54 } 55 } 56 int x=0; 57 while(f[x]!=-1) 58 x=f[x];//找到整棵树的根节点 59 dfs(x); 60 int minn=min(dp[x][0],dp[x][1]); 61 printf("%d\n",minn); 62 } 63 return 0; 64 }