题解 | #寻找牛妹#
寻找牛妹
http://www.nowcoder.com/practice/840e145d951341738a4ea56e14695958
一.题目描述
NC571寻找牛妹
n个结点之间有n-1条边,有一个目标数组X,其中有m个目标结点,从根结点走到每个目标结点Xi,每条边最多可以走两次,问从根结点走到每一个目标节点最多可以经过几条边?
二.算法(暴力搜索)
首先我们要理解题意,但对于n个节点之间有n-1条边我们可以认为其是一个树,由于其连通性我们可以做出如下分析:
,下面我们利用暴力搜索来解决,下面给出完整代码:
class Solution {
public:
int num[200005];//记录孩子个数(并不是一层而是下方全部)
int dis[200005];//记录距离
vector<int>mp[200005];
vector<int> solve(int n, int m, vector<int>& u, vector<int>& v, vector<int>& x) {
for(int i=0;i<n-1;i++){
//记录双向边
mp[u[i]].push_back(v[i]);
mp[v[i]].push_back(u[i]);
}
vector<int>cn(m);
int ans=2*(u.size()-1);
dfs(1,0,0);
for(int i=0;i<m;i++){
//利用前面推导公式计算
cn[i]=ans-dis[x[i]]-2*(num[x[i]]-1);
}
return cn;
}
int dfs(int now,int pre,int cn){
//now表示当前搜索结点,pre表示前一次搜索的节点,cn表示当前结点到根结点的距离
dis[now]=cn;
int sum=0;
for(auto &j:mp[now]){
if(j!=pre){
sum+=dfs(j,now,cn+1)+1;
}
}
num[now]=sum;
return sum;
}
};时间复杂度: 对于每一个节点只有一次访问
空间复杂度: 利用了二维vector来存图
优缺点:代码实现简单,但是利用的公式推导难理解
三.算法(java实现)
可以利用java的ArrayList来代替c++的vector来实现,思路相同,下面是完整代码:
import java.util.*;
public class Solution {
ArrayList<Integer>[]mp;
int[]dis;
int[]num;
public int[] solve (int n, int m, int[] u, int[] v, int[] x) {
//对数组和ArrList分配空间
mp=new ArrayList[n+1];
dis=new int[n+1];
num=new int[n+1];
int[]cn=new int[m];
for(int i=1;i<=n;i++){
mp[i]=new ArrayList<>();
}
for(int i=0;i<n-1;i++){
//双向边
mp[u[i]].add(v[i]);
mp[v[i]].add(u[i]);
}
dfs(1,0,0);
int sum=2*(u.length-1);
for(int i=0;i<m;i++){
//利用推导公式
cn[i]=sum-dis[x[i]]-(num[x[i]]-1)*2;
}
return cn;
}
int dfs(int now,int pre,int cn){
//now表示当前搜索结点,pre表示前一次搜索的节点,cn表示当前结点到根结点的距离
dis[now]=cn;
int cnt=0;
for(int j:mp[now]){
if(j!=pre){
cnt+=dfs(j,now,cn+1)+1;
}
}
num[now]=cnt;
return cnt;
}
}时间复杂度: 对于每一个节点只有一次访问
空间复杂度: 利用了ArrayList二维来存图
优缺点:代码实现简单,但是利用的公式推导难理解


