数据结构作业——sights(最短路/最近公共祖先)

sights

Description

美丽的小风姑娘打算去旅游散心,她走进了一座山,发现这座山有 n 个景点,由于山路难修,所以施工队只修了最少条的路,来保证 n 个景点联通,娇弱的小风姑娘不想走那么长的山路, 所以打算乘坐专用的交通工具。 有的景点之间有路,乘坐交通工具需要花费一定的金额。由于到达景区之前已经花了一部分钱了,现在可爱的小风姑娘站在景点 1,即根景点。按原计划她要去编号为 m 的景点,导游告诉她到景点 m 总共要花的钱(包括来之前花的钱) 。然而善变的小风姑娘突然想去景点 y(直接从景点 1 到景点 y) ,所以她想要知道到景点 y 总共要花多少钱,作为程序员之花,她想用代码来解决这个问题。

Input

输入第一行为一个正整数 n 表示景点的数目,景点从 1 到 n 编号。
接下来 n-1 行,代表山路,每行三个整数 x,y,p,分别表示 x,y 景点间的路费。
第 n+1 行一个整数 q 表示询问组数。每组数据独立互不相关。
紧跟着 q 行,每行三个整数 m,v,y,分别表示 m 景点的编号,到达 m 景点的总花费 v,以及要求的 y 景点。
30%的数据 n<=20,p<=100,q<=10
70%的数据 n<=1000,p<=10000,q<=100
100%的数据 n<=100000,p<=1000000,q<=n

Output

输出 q 行,每行一个整数表示题目要求的答案,由于答案可能很大,输出对
707063423 取余的结果。

Sample Input

41 2 51 3 62 4 422 8 43 6 2

Sample Output

125

思路

跑一遍spfa记录下到各个节点的距离。也可以通过最近公共祖先解决问题。

 AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef __int64 LL;
const int maxn = 100010;
const LL mod = 707063423;
const LL INF = 0xffffffff;
struct Edge{
	int u,v,next;
	LL w;
}edge[2*maxn];
int tot = 0,head[maxn];
LL dis[maxn];
bool vis[maxn];

void addedge(int u,int v,LL w)
{
	edge[tot].u = u;edge[tot].v = v;edge[tot].w = w;edge[tot].next = head[u];
	head[u] = tot++;
}

void spfa(int N)
{
	int i;
	memset(vis,false,sizeof(vis));
	for (i = 0;i <= N;i++)	dis[i] = INF;
	queue<int>que;
	while (!que.empty())	que.pop();
	dis[1] = 0;
	que.push(1);
	vis[1] = true;
	while (!que.empty())
	{
		int u = que.front();
		que.pop();
		vis[u] = false;
		for (i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].v;
			if (dis[u] + edge[i].w < dis[v])
			{
				dis[v] = dis[u] + edge[i].w;
				if (!vis[v])
				{
					que.push(v);
					vis[v] = true;
				}
			}
		}
	}
}

int main()
{
	//freopen("data.txt","r",stdin);
	//freopen("2.txt","w",stdout);
	int N,u,v,q,m,y,i;
	LL w,cv;
	memset(head,-1,sizeof(head));
	scanf("%d",&N);
	for (i = 0;i < N - 1;i++)
	{
		scanf("%d%d%I64d",&u,&v,&w);
		addedge(u,v,w);
		addedge(v,u,w);
	}
	spfa(N);
	scanf("%d",&q);
	while (q--)
	{
		scanf("%d%I64d%d",&m,&cv,&y);
		cv = (cv - dis[m] + mod)%mod;
		printf("%I64d\n",(dis[y]%mod + cv%mod)%mod);
	}
	return 0;
}

对拍程序

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<time.h>
const int maxn = 100000;
const int maxx = 1000000;

int main()
{
	freopen("data.txt","w",stdout);
	srand(time(NULL));
	int N;
	N = rand();
	printf("%d\n",N);
	for (int i = 2;i <= N;i++)
	{
		int leave = rand()%i;
		while (!leave)
		{
			leave = rand()%i;
		}
		printf("%d %d %d\n",leave,i,rand()%maxx);
	}
	int M = rand()%maxn;
	printf("%d\n",M);
	while (M--)
	{
		printf("%d %d %d\n",rand()%N + 1,rand(),rand()%N+1);
	}
	return 0;
}

  

 

时间: 2024-10-11 15:00:36

数据结构作业——sights(最短路/最近公共祖先)的相关文章

数据结构问题集锦 - 最小公共祖先问题

作为一个工程党,在各路竞赛大神的面前总会感到自己实力的捉急.大神总是能够根据问题的不同,轻而易举地给出问题的解法,然而我这种渣渣只能用所谓的”直观方法“聊以自慰,说多了都是泪啊.However,正视自己理论方面的不足,迎头赶上还是必要的,毕竟要真正踏入业界,理论知识是不能少的啊.(比如各种语言的Hash Map,它们的核心可都是红黑树啊) 既然助教要求博文要直观,通俗易懂,那就让我们递归这种方法开始.方法一:递归法 按照题目的要求,如果某两个节点具有同一个公共祖先的话,那么会存在两种情况:要么其

HDU2874 Connections between cities 最近公共祖先+离线

给了你n个村庄把,然后m条路径,q个询问,问你两个点之间的最短距离 分析:由于按照题意来说本图是没有环的,所以求a,b的最近公共祖先 到他们的各自的距离之和就是 那个他们的最短路啦,用的是tarjan来做的,我的方法定义了一个dis数组来随时记录路径的长度,其它大神各有自己的神奇之法 #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstri

最近公共祖先 tarjan离线算法 C++

最近做到一道题目,大概的意思就是求一个多叉树中两个节点的最近公共祖先,输入是用邻接矩阵表示的. 要想理解tarjan算法并实现它,需要先理解一下内容: 1) 深度优先搜索:tarjan算法核心思想:当某节点刚刚搜索完毕时,看与其相关的结点v是否已经被访问,如果v已经被访问过了,则它们的最近公共祖先就是v的祖先. 2) 并查集原理和实现方法,并查集的代表和祖先的区别(其实也可以一起表示),祖先的更新时刻 3) 如何表示多叉数(邻接链表,邻接矩阵),如何表示查询对,如何记录查询结果 下面是c++实现

最小公共祖先lca

3.神秘国度的爱情故事 题目要求:某个太空神秘国度中有很多美丽的小村,从太空中可以想见,小村间有路相连,更精确一点说,任意两村之间有且仅有一条路径.小村 A 中有位年轻人爱上了自己村里的美丽姑娘.每天早晨,姑娘都会去小村 B 里的面包房工作,傍晚 6 点回到家.年轻人终于决定要向姑娘表白,他打算在小村 C 等着姑娘路过的时候把爱慕说出来.问题是,他不能确定小村 C 是否在小村 B 到小村 A 之间的路径上.你可以帮他解决这个问题吗? 输入要求:输入由若干组测试数据组成.每组数据的第 1 行包含一

从零开始的LCA(最近公共祖先)

清明在机房听学长讲树上差分时提到了 \(LCA\) 这个东西,就顺带着学习了一波.由于本人是个蒟蒻,为了避免出现看不懂自己写的 \(Blog\) 这种情况,文中涉及到的知识概念都会 概括性地 讲一下. 先甩个定义 \(LCA\) \((Lowest\) \(Common\) \(Ancestors)\) 即最近公共祖先,是指在一个树或者有向无环图中同时拥有 \(v\) 和 \(w\) 作为后代的最深的节点,.在这里,我们定义一个节点也是其自己的后代,因此如果 \(v\) 是 \(w\) 的后代,

UOJ #226.最近公共祖先

[题目描述]: 有根树在计算机科学工程领域是一个人人熟知的数据结构类型.下面是一个例子. 8->(1,4,5):1->(13,14):4->(6,10):5->(9):6->(7,15):10->(2,11,16):16->(3,12): 在这个图中,每个点都是由{1, 2,...,16}中的某个数字标记的.8号点是树的根.如果x号点在y号点到根的路径上,则x是y的祖先.比如4是16的祖先,10也是.事实上,8,4,10,16都是16的祖先.记住,一个节点本身就是

线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板

线段树(区间修改,区间和): #include <cstdio> #include <iostream> #include <cstring> using namespace std; int c[1000000],n,m; char s; void update(int p,int l,int r,int x,int add) { int m=(l+r) / 2; if (l==r) { c[p]+=add; return; } if (x<=m) update

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

50、树中两个节点的公共祖先

详细的询问: 1.该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/) 思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历:找到当前节点在两个输入大小之间,当前节点就是. 递归和非递归 public class Solution { public TreeNode lowestCommonAncestor(TreeNo