zoukankan      html  css  js  c++  java
  • 洛谷P3252 [JLOI2012]树

    题目描述

    在这个问题中,给定一个值S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到S。路径中节点的深度必须是升序的。假设节点1是根节点,根的深度是0,它的儿子节点的深度为1。路径不必一定从根节点开始。

    输入输出格式

    输入格式:

     

    第一行是两个整数N和S,其中N是树的节点数。 第二行是N个正整数,第i个整数表示节点i的正整数。 接下来的N-1行每行是2个整数x和y,表示y是x的儿子。

     

    输出格式:

     

    输出路径节点总和为S的路径数量。

     

    输入输出样例

    输入样例#1:
    3 3
    1 2 3
    1 2
    1 3
    输出样例#1:
    2

    说明

    对于100%数据,N<=100000,所有权值以及S都不超过1000。

    题目大意:求树上连续一段深度递增的路径的点权和为s的条数

    题解:dfs(i)以i为起点的路径有多少条 

    错因:理解错了 不能用记忆化搜索

    数据水暴力可过

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define LL long long
    #define maxn 100008
    using namespace std;
    
    int n,s,sumedge;
    int head[maxn],w[maxn];
    long long ans;
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    LL dfs(int x,int sum){
        if(sum>s)return 0;
        if(sum==s)return 1;
        long long js=0;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            js+=dfs(v,sum+w[v]);
        }
        return js;
    }
    
    int main(){
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        for(int i=1;i<=n;i++)if(w[i]==s)ans++;else ans+=dfs(i,w[i]);
        cout<<ans<<endl;
        return 0;
    }

    树上前缀和

    保存搜到i之前的祖先,累加权值,是否sum[i]-sum[祖先]=s,注意搜完时删掉祖先。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100008
    #define LL long long
    using namespace std;
    
    int n,s,sumedge,cnt,js;
    int head[maxn],w[maxn],dad[maxn],fa[maxn],sum[maxn];
    LL ans;
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    void dfs(int x){
        dad[++js]=x;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            sum[v]=sum[x]+w[v];
            for(int j=js;j>=0;j--){//要循环到0,可能它自己的点权就是s 
                if(sum[v]-sum[dad[j]]==s)ans++;
                if(sum[v]-sum[dad[j]]>s)break;
            }
            dfs(v);
        }
        js--;
    }
    
    int main(){
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            fa[y]=x;
            add(x,y);
        }
        sum[1]=w[1]; 
        dfs(1);
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    oracle里某列插入多行数据
    子类与父类的一些关系
    math.round()的值怎么取的
    oracle replace函数
    spring5.1.5使用的jackson依赖版本
    eclipse设置新建jsp页面的默认编码为utf-8
    c3p0启动失败
    sql的左联右联合内联的区别
    eclipse安装spring tools插件的问题
    HTML点击按钮button跳转页面的四种方法
  • 原文地址:https://www.cnblogs.com/zzyh/p/7593079.html
Copyright © 2011-2022 走看看