poj 3689 树形dp
思路: 每个点有三种状态,本身有塔,被子节点的塔覆盖,被父节点的塔覆盖。
#include<map> #include<set> #include<cmath> #include<queue> #include<cstdio> #include<vector> #include<string> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define Maxn 10100 #define Maxm 100010 #define LL __int64 #define Abs(x) ((x)>0?(x):(-x)) #define lson(x) (x<<1) #define rson(x) (x<<1|1) #define inf 1000000 #define Mod 1000000007 using namespace std; int dp[Maxn][3],head[Maxn],vi[Maxn],e; struct Edge{ int u,v,val,next; }edge[Maxn*2]; void init() { memset(dp,0,sizeof(dp)); memset(head,-1,sizeof(head)); memset(vi,0,sizeof(vi)); e=0; } void add(int u,int v) { edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++; edge[e].u=v,edge[e].v=u,edge[e].next=head[v],head[v]=e++; } inline int min(int a,int b,int c) { a=a<b?a:b; return a<c?a:c; } void dfs(int u) { int i,v; vi[u]=1; dp[u][0]=1;//有信息塔 dp[u][1]=0;//由前覆盖 dp[u][2]=0;//由后覆盖 int sum=0,f=0,min1=inf; for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(vi[v]) continue; dfs(v); dp[u][0]+=min(dp[v][0],dp[v][1],dp[v][2]); dp[u][2]+=min(dp[v][1],dp[v][0]); if(dp[v][0]<=dp[v][1]){ sum+=dp[v][0]; f=1; } else{ if(dp[v][0]-dp[v][1]<min1){ min1=dp[v][0]-dp[v][1]; } sum+=dp[v][1]; } } if(f) dp[u][1]=sum; else dp[u][1]=sum+min1; } int main() { int n,i,j,u,v; while(scanf("%d",&n)!=EOF){ init(); for(i=1;i<n;i++){ scanf("%d%d",&u,&v); add(u,v); } dfs(1); printf("%d\n",min(dp[1][0],dp[1][1])); } return 0; }