感觉树的题目做多了,每题都会往树形dp想。
题目大意:
给定一棵n个点的树,问其中有多少条长度为偶数的路径。路径的长度为经过的边的条数。x到y与y到x被视为同一条路径。路径的起点与终点不能相同。
思路:
第一反应是使用dfs计算每个点下面的奇数路径和偶数路径的数量。
令f[i][0/1]表示从i出发到子树的偶数路径数和奇数路劲数。
显然对于相邻的边(u,v)我们有:
f[u][0]+=f[v][1]
f[u][1]+=f[v][0]+1 //u->v是奇数边
这个我们一遍dfs可以解决。
接着我们考虑枚举每一个点x,然后答案是∑f[x][0]
但是由于我们前面处理的f[x][0]是从x出发往子树的走的,我们依然要考虑往根方向的路。
那么对于边(x,y),我们可以进行转移:
f[y][0]+=f[x][1]-f[y][0]-1
f[y][1]+=f[x][0]-f[y][1]+1
这样子计算的话,我们会把一条边计算两边,所以最后ans/2就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,d[100040];
long long ans,f[100040][2];
vector<int>vt[100040];
void dfs(int x,int fa){
for(int i=0;i<vt[x].size();i++){
int y=vt[x][i];
if(y==fa)continue;
dfs(y,x);
if(d[y]==1){
f[x][0]+=0;
f[x][1]+=1;
continue;
}
f[x][0]+=f[y][1];
f[x][1]+=f[y][0]+1;
}
return ;
}
void dfs2(int x,int fa){
ans+=f[x][0];
for(int i=0;i<vt[x].size();i++){
int y=vt[x][i];
if(y==fa)continue;
f[y][0]+=f[x][1]-f[y][0]-1;
f[y][1]+=f[x][0]-f[y][1]+1;
dfs2(y,x);
}
}
int main()
{
cin>>n;
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
vt[x].push_back(y);
vt[y].push_back(x);
d[x]++;d[y]++;
}
dfs(1,-1);
dfs2(1,-1);
cout<<ans/2<<endl;
return 0;
}写完去看了眼题解,好家伙,题解也太简单了。
原来只要去计算一下奇数深度的点数量和偶数深度的点数量,然后计算就可以了。
因为奇数+奇数=偶数,偶数+偶数=偶数。
这里代码就不贴了。感觉可以作为思维题进行考查。

京公网安备 11010502036488号