题目大意:给你一棵树,n个节点,现在需要照亮所有的边,问你最少需要在节点上放几个士兵?
思路:最简单的树形DP了吧,设d[ i ][ j ] 把表示节点i,状态为j时的把以i为根节点的子树的边全部照亮的最小值,j==0表示i节点不放兵,1表示放兵,那么d[ i ][ 0 ] = SIGMA(d[ v ][ 1 ]),d[ i ][ 1 ] = SIGMA(min(d[ v ][ 0 ],d[ v ][ 1 ])),v为i的子节点。
就是输入有点坑,又要抠。。 = =
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1555 ; struct Edge { int t,next; } edge[MAXN<<1]; int tot,head[MAXN]; void add_edge(int s,int t) { edge[tot].t=t; edge[tot].next = head[s]; head[s] = tot++; } int d[MAXN][3]; void dfs(int u,int fa) { d[u][0] = 0; d[u][1] = 1; for(int e = head[u];e!=-1;e = edge[e].next) { int v = edge[e].t; if(v == fa) continue; dfs(v,u); d[u][0] += d[v][1]; d[u][1] += min(d[v][0],d[v][1]); } } char str[111]; int main() { int n; while(~scanf("%d",&n)) { tot=0; memset(head,-1,sizeof(head)); for(int i = 0;i<n;i++) { scanf("%s",str); int flag = 0; int s,m; for(int j=0;str[j]!='\0';) { if(str[j]>='0'&&str[j]<='9') { int tmp = str[j]-'0'; j++; while(str[j]>='0'&&str[j]<='9') { tmp = tmp*10 + str[j]-'0'; j++; } //printf("tmp = %d\n",tmp); if(flag==0) { s = tmp; flag ++; } else if(flag==1) { m = tmp; } } else j++; } //printf("s = %d.m = %d\n",s,m); int a; for(int j = 0;j<m;j++) { scanf("%d",&a); add_edge(s,a); add_edge(a,s); } } dfs(0,-1); printf("%d\n",min(d[0][0],d[0][1])); } return 0; }