题意:给你一颗树,然后在数的结点上进行标记,一个结点被标记之后,连接它的边也被标记,最少标记几个点可以把所有的边标记。
思路:树形dp,和刘汝佳白书70页放置街灯一样。dp[u][1]表示在u结点标记,dp[u][0]表示在u结点不标记。
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <cmath> 5 #include <algorithm> 6 #define maxn 100010 7 using namespace std; 8 9 int n,m; 10 vector<int>g[maxn]; 11 int dp[maxn][2]; 12 13 int dfs(int u,int c,int fa) 14 { 15 if(dp[u][c]>=0) return dp[u][c]; 16 int &ans=dp[u][c]; 17 ans=2000; 18 for(int i=0; i<(int)g[u].size(); i++) 19 { 20 int v1=g[u][i]; 21 if(v1!=fa) 22 ans+=dfs(v1,1,u); 23 } 24 if(c==1||fa==-1) 25 { 26 int sum=0; 27 for(int i=0; i<(int)g[u].size(); i++) 28 { 29 int v=g[u][i]; 30 if(v!=fa) 31 { 32 sum+=dfs(v,0,u); 33 sum++; 34 } 35 } 36 if(fa>=0) sum++; 37 ans=min(ans,sum); 38 } 39 return ans; 40 } 41 42 int main() 43 { 44 while(scanf("%d",&n)!=EOF) 45 { 46 for(int i=0; i<=n; i++) 47 { 48 g[i].clear(); 49 } 50 for(int i=1; i<=n; i++) 51 { 52 int u,cnt,v; 53 scanf("%d:(%d)",&u,&cnt); 54 while(cnt--) 55 { 56 scanf("%d",&v); 57 g[u].push_back(v); 58 g[v].push_back(u); 59 } 60 } 61 int ans=0; 62 memset(dp,-1,sizeof(dp)); 63 for(int i=0; i<n; i++) 64 { 65 if(dp[i][1]==-1) ans+=dfs(i,0,-1); 66 } 67 printf("%d ",ans/2000); 68 } 69 return 0; 70 }