HDOJ 2856 How far away ?

1 篇文章 0 订阅

题目描述:

There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.

输出格式:

For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.

输入数据:

2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1

输出数据:

10
25
100
100

解析

  1. 题目大意:

城镇之间互相有道路(双向边),且只存在n-1条边,保证相互可达,求两点
之间的距离。

  1. 思路:

解法一: vector邻接表 + dfs

算法一:vector邻接表 + dfs 
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#define min(x,y) (x<y?x:y)
const int N = 40005, inf = 0x3f3f3f3f;
struct Edge{
  int from, to, weight;
  Edge(){}
  Edge(int from, int to, int weight) {
    this->from = from;
    this->to = to;
    this->weight = weight;
  }
};
vector<Edge> Map[N];
int ans, vis[N];
void dfs(int x,int y, int sum) ;
int main() {
  int t;
  cin >> t;
  while (t--) {
    int n, m;
    cin >> n >> m;
    
    int from, to, len;
    for (int i = 0; i < n-1; i++) {
      cin >> from >> to >> len;
      Map[from].push_back(Edge(from,to,len));
      Map[to].push_back(Edge(to,from,len));
    }
    
    int x, y;
    for (int i = 0; i < m; i++) {
      cin >> x >> y;
      ans = inf;
      memset(vis,0,sizeof(vis));
      dfs(x,y,0);
      cout << ans << endl;
    }
    for (int i = 1; i <= n; i++) Map[i].clear();
  }
}
void dfs(int x,int y, int sum) {
  if (x == y) {
    ans = min(ans,sum);
  }
  if (sum > ans) return ;
  for (int i = 0; i < Map[x].size(); i++) {
    Edge temp = Map[x][i];
    if (vis[temp.to] == 0) {
      vis[temp.to] = 1;
      dfs(temp.to,y,sum+temp.weight);
      vis[temp.to] = 0;
    }
  }
}

解法二: 无向图(不存在环 即只有n-1条边) 所以可以将该图看作一棵树

转化为LCA裸问题,只需要再一边寻找最近公共祖先的同时,跟
新当前点到根节点的距离dist即可,那么节点u,v之间的距离为
dist[u]+dist[v]-2*dist[lca(u,v)];

//算法二:LCA 最近公共祖先算法 -- 无向图(不存在环  即只有n-1条边)的多组数据的最近公共祖先 
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 40005, M = 205;
struct Edge {
  int from, to, weight;
  Edge(){}
  Edge(int from, int to, int weight) {
    this->from = from;
    this->to = to;
    this->weight = weight;
  }
};
vector<Edge> Map[N];

vector<Edge> Query[N];
int dis[N], f[N], vis[N];
int result[M];
void Targin(int root) ;
int main() {
  int t;
  cin >> t;
  while (t--) {
    int n, m;
    cin >> n >> m;
    int from, to, len;
    for (int i = 0; i < n-1; i++) {
      f[i+1] = i+1;
      cin >> from >> to >> len;
      Map[from].push_back(Edge(from,to,len));
      Map[to].push_back(Edge(to,from,len));
    }
    for (int i = 0; i < m; i++) {
      cin >> from >> to;
      Query[from].push_back(Edge(from,to,i));
      Query[to].push_back(Edge(to,from,i));
    } 
//    memset(dis,0,sizeof(dis));
    dis[1] = 0;
    memset(vis,0,sizeof(vis));
    Targin(1);
    for (int i = 0; i < m; i++) {
      cout << result[i] << endl;
    }
    for (int i = 1; i <= n; i++) {
      Query[i].clear();
      Map[i].clear();
    }
  }
}
int GetFather(int x) {
  int v = x;
  while (v != f[v]) {
    v = f[v];
  }
  int i = x, j;
  while(i != v) {
    j = f[i];
    f[i] = v;
    i = j;
  }
  return v;
}
void Union(int x,int y) {
  int fx = GetFather(x), fy = GetFather(y);
  if (fx != fy) {
    f[fy] = fx;
  }
}
void Targin(int root) {
  
  vis[root] = 1;
  for (int i = 0; i < Map[root].size(); i++) {
    Edge temp = Map[root][i];
    
    if (vis[temp.to] == 0) { // 这里是无向图 双向边  如果不用vis 数组记录 则会无限循环 
//      cout << root << "-" << temp.to << "-" << temp.weight << endl;
      dis[temp.to] = dis[root] + temp.weight;
      Targin(temp.to);
      Union(root,temp.to);  
    }
  }
  
  for (int i = 0; i < Query[root].size(); i++) {
    Edge temp = Query[root][i];
//    cout << root << "--" << temp.to << endl;
    if (vis[temp.to] == 1) {
      int LCA = GetFather(temp.to);
//      cout << LCA << "--" <<  dis[temp.to] << "--" <<  dis[root] << endl;
      result[temp.weight] = dis[temp.to] + dis[root] - 2*dis[LCA];
    }
  }

}

参考链接:http://www.cnblogs.com/lemonbiscuit/p/7859413.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值