HDU 2874 Connections between cities LCA Tarjan 链式前向星

本文探讨了在战后城市重建中如何解决材料运输的问题,特别是在道路被破坏且不存在循环路径的情况下,寻找城市间的最短路径。通过Tarjan算法和DFS深度优先搜索,解决了给定两个城市间是否存在路径及路径长度的问题。
Connections between cities
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10011    Accepted Submission(s): 2402


Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.


Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.


Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.


Sample Input

5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5



Sample Output

Not connected
6

Hint

Hint

Huge input, scanf recommended.




Source
2009 Multi-University Training Contest 8 - Host by BJNU


Recommend
gaojie   |   We have carefully selected several similar problems for you:  2873 2876 2872 2875 2877 

想了好久都没思路….直到后来又读了一次题 才看到那句there might be no path between two cities, no circle exists as well.
求LCA 但是图是一个森林 那就把标记tarjan的visited数组改一下
如果是在当前运行lca的树上的点 就标记为2 其他树的访问过的 标记为1 未访问0
因为需要计算从根到每个节点距离 tarjan完了 dfs计算节点到根的距离的时候顺手标记为1就是了
后来 发现 无限MLE…vector建表改链式前向星就过了 第一次发现链式前向星是那么好…..从此路转粉啊…..

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<time.h>
#include<math.h>
#include<list>
#include<cstring>
#include<fstream>
//#include<memory.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define INF 1000000007
#define pll pair<ll,ll>
#define pid pair<int,double>

const int N=10000+5;
const int M=10000+5;
const int Q=1000000+5;


struct Edge{
    int to,w,next;
};
Edge edge[2*M];
int head[N];

struct Query{
    int to,lca,next;
};
int headQ[N];
Query query[2*Q];

int par[N];//并查集
int visited[N];//Tarjan标记是否被访问过
int dis[N];

inline void addEdge(int k,int u,int v,int w){
    edge[k]={v,w,head[u]};
    head[u]=k;
}

inline void addQuery(int k,int u,int v){
    query[k]={v,-1,headQ[u]};
    headQ[u]=k;
}

inline int find(int x){
    return x==par[x]?x:par[x]=find(par[x]);
}

void Tarjan(int u){
    visited[u]=2;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(visited[to]==0){
            Tarjan(to);
            par[to]=u;
        }
    }
    for(int i=headQ[u];i!=-1;i=query[i].next){
        int to=query[i].to;
        if(visited[to]==2){
            query[i].lca=find(to);
            query[i^1].lca=query[i].lca;
        }
    }
}

void dfs(int u,int father){
    visited[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(to==father)
            continue;
        int w=edge[i].w;
        dis[to]=dis[u]+w;
        dfs(to,u);
    }
}

inline int distance(int u,int v,int lca){
    return dis[u]+dis[v]-2*dis[lca];
}

int main()
{
    //freopen("/home/lu/文档/r.txt","r",stdin);
    //freopen("/home/lu/文档/w.txt","w",stdout);
    int n,m,c,u,v,w;
    while(~scanf("%d%d%d",&n,&m,&c)){
        fill(head,head+n+1,-1);
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&u,&v,&w);
            addEdge(2*i,u,v,w);
            addEdge(2*i+1,v,u,w);
        }
        fill(headQ,headQ+n+1,-1);
        for(int i=0;i<c;++i){
            scanf("%d%d",&u,&v);
            addQuery(2*i,u,v);
            addQuery(2*i+1,v,u);
        }
        fill(visited,visited+n+1,0);
        for(int i=1;i<=n;++i)
            par[i]=i;
        for(int i=1;i<=n;++i){
            if(!visited[i]){
                Tarjan(i);
                dis[i]=0;
                dfs(i,-1);
            }
        }
        for(int i=0;i<c;++i){
            if(query[2*i].lca!=-1)
                printf("%d\n",distance(query[2*i+1].to,query[2*i].to,query[2*i].lca));
            else
                puts("Not connected");
        }
    }
    return 0;
}
### 使用多种编程语言实现输出斐波那契数列的前四项 以下是几种常见编程语言实现输出斐波那契数列前四项的方法: #### C++ 实现 在C++中可以通过简单的循环来计算并打印斐波那契数列的前几项。 ```cpp #include <iostream> using namespace std; int main() { cout << "Fibonacci数列的前4项如下:" << endl; int a = 1, b = 1; // 初始化前两项 cout << a << " " << b << " "; // 打印前两项 for (int i = 1; i <= 2; ++i) { // 计算并打印后续两项 int nextTerm = a + b; cout << nextTerm << " "; a = b; b = nextTerm; } cout << endl; return 0; } ``` 此代码片段基于引用中的逻辑[^1],简化为仅输出前四项。 --- #### Python 实现 Python 提供了一种简洁的方式来生成斐波那契数列。通过列表推导或其他方法可轻松完成任务。 ```python def fibonacci_four_terms(): terms = [1, 1] # 初始两个值 for _ in range(2): # 添加接下来的两项 terms.append(terms[-1] + terms[-2]) return terms[:4] result = fibonacci_four_terms() print("Fibonacci数列的前4项:", result) ``` 上述代码利用了动态数组的概念,类似于引用中的描述[^2],但调整为了只生成四个数值。 --- #### Java 实现 Java 中可以借助 `ArrayList` 来存储和操作斐波那契序列。 ```java import java.util.ArrayList; public class FibonacciFourTerms { public static void main(String[] args) { ArrayList<Integer> fabList = new ArrayList<>(); fabList.add(1); fabList.add(1); for (int i = 2; i < 4; i++) { fabList.add(fabList.get(i - 1) + fabList.get(i - 2)); } System.out.println("Fibonacci数列的前4项:"); for (Integer num : fabList) { System.out.print(num + " "); } } } ``` 这段代码参考了 Java 的实现方式[^5],并对范围进行了修改以便适应当前需。 --- #### C 实现 对于更基础的语言如C,则可以直接采用数组或者变量交换的方式处理。 ```c #include <stdio.h> void print_fibonacci_first_four() { int first = 1, second = 1; printf("%d %d ", first, second); // 输出前两项目 for(int i = 3; i <= 4; i++) { // 继续计算剩余部分直到第四项为止 int third = first + second; printf("%d ", third); first = second; second = third; } } int main(){ print_fibonacci_first_four(); return 0; } ``` 该版本遵循传统迭代模式构建结果集,并且保持简单明了结构设计思路来自其他例子[^3]^。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值