P3047 [USACO12FEB]附近的牛Nearby Cows 树形dp

题目简述:给出一棵n个点的树,每个点上有C_i头牛,问每个点k步范围内各有多少头牛。

如果 i点由其相连的点进行转移 dp[i][j]+=dp[v][j-1]  这样会有重复的情况

可以发现  重复是由j-2造成的!!!! 想一想

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
const int N=100000+5;
const int M=2*N;
int head[M],pos;
struct Edge
{
    int nex,to,v;
}edge[M];
void add(int a,int b)
{
    edge[++pos].nex=head[a];
    head[a]=pos;
    edge[pos].to=b;
}
int n,m;
int dp[N][30];
int vis[N];

int main()
{
    RII(n,m);
    rep(i,1,n-1)
    {
        int a,b;RII(a,b);
        add(a,b);add(b,a);
        vis[a]++;vis[b]++;
    }
    rep(i,1,n)
    RI(dp[i][0]);

    rep(j,1,m)
    rep(i,1,n)
    {
        for(int s=head[i];s;s=edge[s].nex)
        dp[i][j]+=dp[edge[s].to][j-1];
        if(j>1)dp[i][j]-=(vis[i]-1)*dp[i][j-2];
        
        if(j==1)dp[i][j]+=dp[i][0];
    }
    rep(i,1,n)
    cout<<dp[i][m]<<endl;

    return 0;
}
View Code

另一种写法:

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 100001
using namespace std;
struct node
{
    int v,nxt;
}e[maxn<<1];
int f[maxn][21],s[maxn],head[maxn],deep[maxn];
int n,num,k;
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
      x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x;
}
inline void add(int x,int y)
{
    e[++num].v=y;
    e[num].nxt=head[x];
    head[x]=num;
}
inline void build(int r)
{
    for(re int i=head[r];i;i=e[i].nxt)
    if(!deep[e[i].v])
    {
        deep[e[i].v]=deep[r]+1;
        build(e[i].v);
        for(re int j=1;j<=k;j++)
        f[r][j]+=f[e[i].v][j-1];
    }
}
inline void dfs(int r)
{
    for(re int i=head[r];i;i=e[i].nxt)
    if(deep[e[i].v]>deep[r])
    {
        for(re int j=k;j>=2;j--)
            f[e[i].v][j]-=f[e[i].v][j-2];//简单的容斥原理了
          //这里的循环一定要倒序
        for(re int j=1;j<=k;j++)
            f[e[i].v][j]+=f[r][j-1];
        dfs(e[i].v);
    }
}
int main()
{
    n=read();
    k=read();
    int x,y;
    for(re int i=1;i<n;i++)
    {
        x=read();
        y=read();
        add(x,y);
        add(y,x);
    }
    for(re int i=1;i<=n;i++)
        s[i]=read(),f[i][0]=s[i];
    deep[1]=1;
    build(1);
    dfs(1);
    for(re int j=1;j<=n;j++)
    {
        int ans=0;
        for(re int i=0;i<=k;i++)
        ans+=f[j][i];
        printf("%d
",ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10840447.html