http://acm.hdu.edu.cn/showproblem.php?pid=5290
题意:
一棵树,每个点有一个权值wi,选择点i即可破坏所有距离点i<=wi的点,问破坏所有点 最少需要选择多少个点
题解:同JLOI2016 侦察守卫
http://www.cnblogs.com/TheRoadToTheGold/p/8544819.html
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define N 100001 int d; int w[N]; bool use[N]; int front[N],to[N<<1],nxt[N<<1],tot; int f[N][102],g[N][102]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } void dfs(int x,int fa) { for(int i=0;i<=w[x];++i) f[x][i]=1; for(int i=w[x]+1;i<=101;++i) f[x][i]=N+1; g[x][0]=1; for(int i=1;i<=101;++i) g[x][i]=0; int t; for(int i=front[x];i;i=nxt[i]) { t=to[i]; if(t!=fa) { dfs(t,x); for(int j=0;j<=100;++j) f[x][j]=min(f[x][j]+g[t][j],f[t][j+1]+g[x][j+1]); for(int j=100;j>=0;--j) f[x][j]=min(f[x][j],f[x][j+1]); g[x][0]=f[x][0]; for(int j=1;j<=100;++j) g[x][j]+=g[t][j-1]; for(int j=1;j<=100;++j) g[x][j]=min(g[x][j],g[x][j-1]); } } } int main() { int n,m,u,v; while(scanf("%d",&n)!=EOF) { tot=0; memset(front,0,sizeof(front)); for(int i=1;i<=n;++i) read(w[i]); int u,v; for(int i=1;i<n;++i) { read(u); read(v); add(u,v); } dfs(1,0); printf("%d ",g[1][0]); } return 0; }