Codeforces Round #216 (diy.2) C. Valera and Elections

本文介绍了一种使用树形动态规划(DP)的方法来解决寻找包含特定权重边的路径数量的问题,并记录每条路径中距离起点最远的点。文章详细解释了正确的递归逻辑及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

题意:给一棵树,N-1条边的权值可以是1和2。要找包含权值为2的边的路径有几条,并

           记录这条路径中距离点1最远的点。

分析:

就是树形dp,或者说是树上的记忆化dfs。

开始写dfs,没有从叶子节点开始向前面统计,而是从前往后统计,这样导致统计的结果

有时候偏大。因为返回的时候所有的u都置0,然后这条路径上所有由权值为2的边到达的点

全部算在结果内。


正确的从后往前记录结果:

1、如果是叶子节点且是由权值为2的边到达,则返回1;否则返回0。

2、非叶子节点,如果他的儿子统计的值res为0而它又是通过权值为2的边访问,则return 1。

3、其余情况都return 0。


要注意res的初始化!

开始dfs(1,1),虚拟一个点,通过权值为1的边到点1。


感想:

知道了怎么用vector建邻接表存图。

而且vector数组也可以用memset清零呀~


#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<cctype>
#include<cstdlib>
#include<cmath>
#define INF 0x3f3f3f3f
#define MAX 100010

using namespace std;

struct node
{
    int t;
    int w;
}ve[MAX];

vector<node> a[MAX];
int ans[MAX];
bool vis[MAX];
int u,cnt;

int dfs(int x,int k)
{
    int b,flag=0,r,res=0;
    for(int i=0;i<a[x].size();i++)
    {
        b=a[x][i].t;
        r=a[x][i].w;
        if(vis[b]==0)
        {
            vis[b]=1;
            flag=1;
            res+=dfs(b,r);
        }
    }
    if(!flag)
    {
        if(k==2)
        {
            ans[cnt++]=x;
            return 1;
        }
        return 0;
    }
    if(res==0 && k==2)
    {
        ans[cnt++]=x;
        return 1;
    }
    return res;
}

int main()
{
    int n,s,e,w,t,aaa;
    while(scanf("%d",&n)!=EOF)
    {
        int c=0,aaa=0;
        memset(vis,0,sizeof(vis));
        memset(a,0,sizeof(a));

        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&s,&e,&w);
            ve[c].w=w;
            ve[c].t=e;
            a[s].push_back(ve[c]);

            c++;
            ve[c].w=w;
            ve[c].t=s;
            a[e].push_back(ve[c]);
        }
        u=0;
        cnt=0;

        vis[1]=true;
        aaa=dfs(1,1);
        if(cnt==0)
        {
            printf("0\n");
            continue;
        }
        printf("%d\n",cnt);
        for(int i=0;i<cnt-1;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[cnt-1]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值