题目链接:点击打开链接
题意:给一棵树,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;
}