随笔分类 - 最短路
摘要:题意:很乱分析:把数据处理下,dijkstra下就行了,floyd超时了,我还想着优化一下输入,因为使用了vector和string等等,但是计算数据规模后,处理输入的时间复杂度比floyd要低一个数量级,看来还是要换成dijkstra了。#include #include #include #include #include #include using namespace std;const int N = 205;const int inf = 0x3f3f3f3f; int n, m, D1, D2, A, B;vectorvs[2];int mp1[N][N];int mp2[N][
阅读全文
摘要:题意:给定N个点,现在要求出从1号点到N号点的最短路。题目给的限制条件就是对于某条路径是不能够走的,但是可以选择某段路径走,另外就是所走的路径的标号必须是递增的。分析:由于给定的是一些列的坐标点,这也就说原图其实是一个完全图。对于限制路径,其实只要限制的路径上点数超过2,那么明显可以选择从起点直接走到终点这条最短路来代替限制路径,因此该限制不起作用,而对于限制路径上点数为2的路径则需要标记一下不能够取。对于最终路径要求点坐标路径递增这一条件则直接在floyd处理的时候限制好i,j,k三者的关系即可。#include #include #include #include #include #de
阅读全文
摘要:题意:给定一个图,求从1到N的递增边权的最短路。解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每次将相同权值的边全部取出来一同更新,每条边能够更新的前提是某一个端点在之前被更小的边权更新过。另外一个要注意的地方就是一次相同边的更新中,要把所有的更新暂存起来最后一起去更新,这样是为了防止同一权值的边被多次加入到路径中去。代码如下:#include <cstdlib>#include <cstdio>#include <algorithm>#include &l
阅读全文
摘要:题意:给定N个节点一棵树,现在要求询问任意两点之间的简单路径的距离,其实也就是最短路径距离。解法:spfa:直接对每一对点作一次spfa即可。Tarjan:求出两个点A,B之间的最近公共祖先C,设根到每个点的最短距离为dis[],那么距离就是dis[A]+dis[B]-2*dis[C]。而根到各个点的距离一次dfs就出来了,因此问题转化为求出两点之间的最近公共祖先,Tarjan算法能够离线解决所询问的点对。原理如下:对于一次dfs,当第一次遍历到点u时,那么令set[u] = u。遍历完以u为根的树后,将u所属集合指向双亲节点。接下来查看u的访问列表中有没有询问<u, v>的点对,
阅读全文
摘要:题意:给定一个图,求出两点之间的最短路,但是这个最短路是在一条路径上的某条最贵的边能够忽略的情况下的最小值。分析:直接求出一条最短路再减去这条最短路中的最大值的做法是错误的。例如:如果A-B存在一条(2, 2, 2, 2, 2)的总长为10的路,减去最大值之后是8,存在另外一条路径(1, 8, 2),总长为11,但是减去最大的8之后就是3了,因此这里要用到动态规划来解。设dp[0][i][j]表示从i到j不使用免费权的最短路径,dp[1][i][j]表示使用免费权的最短路径,则有动态方程:dp[1][i][j] = min(dp[0][i][k] + dp[1][k][j], dp[1][i]
阅读全文
摘要:题意:给定一个网络,每条线路都同时有几个公式拥有,现在问某两点之间哪些公司通过自己拥有的路径单独联通。分析:问题开起来是给定了多个图,对他们分别求一个连通性,但是这里把多个图压缩到一个int型数字内,因为这里只是简简单单求一个连通性,使用位运算非常高效。代码如下:#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>using namespace std;int G[205][205];int N;void floyd() { for (int k = 1;
阅读全文
摘要:题意:从若干个S点出发到达T点,稍有不同的是,要区分该点落脚有左脚和右脚两种情况。解法:从题目中给定的S出发,左脚和右脚都可以踏上去,全部入队列后再spfa即可。做了这题发现使用spfa来处理多源点时连超级源点都不用建立了。代码如下:#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;int N, M, dis[2][6
阅读全文
摘要:题意:给定同一个图上的两种路径,求出从某点出发到另一点的路径长度来回长度之比最大的情况。该题对两套图的处理让代码十分恶心,而且最后还要输出路径。计算出最优值最后在计算一次路径,幸好没有要求在相同的情况下按照字典序最小输出。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;int N, M, K;struct
阅读全文
摘要:题意:点与点之间有多条路,并且路是按时开放的,因此需要在边上记录更多的信息。读取一行数时不知道有stringstream类。代码如下:#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>#include <string>using namespace std;const int INF = 0x3f3f3f3f;int N, M, S, T;string str;struct Edge { int v
阅读全文
摘要:这题难就难再要字典序输出,要是单单floyd的话,无法保证最后得到的路径字典序最小,一个简单的反例就是如果6 5 7 8 9和6 8 1 2 9以及6 10 1 2 9同时是6-9的最短路的话,如果忽略相等情况下的更新,6 8之间是不会被7作为中间节点而更新的,但是不忽略的话,又可能被中间比较大的节点更新了。所以直接floyd(采用path[i][j] = k表示i到j通过k点的方式还原路径)是不满足题意的。因此这里采用另外一种记录路径的方式,path[i][j]表示从i到j的第二个元素编号,那么由于仅仅只记录了第二个元素,因此当距离相等的时候,我们就只需要考虑新的“第二个元素”是否更优。这样
阅读全文
摘要:题意:在一个矩形平面内,有若干道墙,现求从左部某一点到右部某一点的最短路径。解法:有一个事实是线路一定是从门两边的点上通过的,不可能出现从中间穿过的可能。因此我们就枚举两两点之间是否可达,这里就要使用到线段相交的判定。构好图之后就是一个spfa搞定。代码如下:#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>using namespace std;int N;struct Wall { double x,
阅读全文
摘要:题意:求一个点到所有点的最短距离之和加上所有点到这个点距离之和,边为单向边。解法:先做一次spfa,然后将所有的边反序做一次spfa即可。代码如下:#include <iostream>#include <cstring>#include <queue>#include <vector>#include <cstdio>using namespace std;const int MaxN = 1000005;int P, Q, idx, gdis[MaxN], cdis[MaxN];int head[MaxN], rhead[MaxN
阅读全文
摘要:题意:给定N个点求1-N的最短路,所加的附加条件就是这N个点前A个点为村庄,后B个点为城堡。马里奥用一双靴子,能够在一定距离(L)内花0时间进行穿梭,且只有K次机会,在这种情况下,求解一个最短路。分析:首先对于如何花费这K次机会是一个动态规划的问题,因此我们需要计算出哪些边允许我们进行无代价的穿梭,由于题目还给定了穿梭只能够从某一点开始/结束,因此必须保证某一路径总长度少于L并且题目中还有一个约束条件要求该路径中间不应该有城堡,因为城堡中有陷阱不能够在穿梭的途中有陷阱。而floyd算法能够很好的就算出哪些路径能够穿梭。解法:首先通过floyd算法从1开始枚举中间点,那么由于前A个节点时村庄,路
阅读全文
摘要:该题又是一个牵涉到节点之间关系通过乘法建立的关系,通过求对数将关系由乘法变为加法应该是可以的。可惜无法无法AC。改为直接相乘却过了。AC代码:#include <iostream>#include <cmath>#include <cstdlib> #include <cstdio>#include <algorithm> #include <cstring>#include <queue>#include <iomanip>using namespace std;/* 一个网络的运送问题,简化之后
阅读全文
摘要:题意:给定一个矩阵,每个元素代表了一个开销,每个位置只能够由上,左,右这些位置传递过来,问从第一行走到最后一行的最少代价为多少.解法:1.最短路 若是用最短路来解这一题,我们需要进行构边,同层相邻的节点连双向边,不同层从上往下连单向边,最后设定一个超级源点和超级终点即可.代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>#include <iostream>#include <algorithm>#include <ve
阅读全文
摘要:这题要处理的地方的就是一个人可以同时向多个人传递消息,也就是说一条消息的传递时间由最长的那一条路径所决定,因为可以同时进行嘛,所以就求某一点到所有点的最短路,然后再寻找一条最长的路劲,枚举每个顶点作为起点就可以了。代码如下:#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<cs
阅读全文
摘要:第二次来做这一题,由于题目中给定了一个等级限制M,所以可以通过枚举第一个点所在的位置求解.思路很清晰.for (int i = 0; i <= M; ++i) 这个i来表示第一个点的等级在M长度区间内的偏移量.然后再在区间内建边,floyd即可.代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#define INF 0x3f3f3f3fusing namespace std;int M
阅读全文
摘要:记录每个节点从四个方向来的最优值,用了那个spfa后,因为要标记入队,所以就会牵涉到一个节点的自环现象,所以这里就直接在队列里面记录其当前距离,不进行队列优化,也过了。该题的边竟然是双向的。代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#include <algorithm>#include <queue>using namespace std;typedef long long int Int64;int N, M, idx, mp[255], head[1500
阅读全文
摘要:这题在比赛的时候没做出来实在是不应该。本来也是用对数处理的,但是后面写的七零八落的。这题也可以直接求,记录每个点最少消耗的流量,剩余流量为初始流量减去这个值,逐步向下迭代。当然这里可以去求他的剩余值,根据公式 最后的流量 L = I * (1-p1) * (1-p2) * ... * (1-pn) 我们对两边同时取对数的话,那么我们就将乘法化成了加法,并且直接求一个最长路就可以了。最后再拿总流量减去最大的剩余量即可。代码如下:#include <cstdio>#include <cstring>#include <cstdlib>#include <q
阅读全文
摘要:跟POJ-1860基本一样,bellman求是否存在环。这里吸取了别人的代码,让bellman算法的外循环直接增加一次,再判定是否在这个过程中有无更新推出的情况。代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#include <map>#include <string>using namespace std;int N, pos, cnt;double dis[35];map<string,int>mp;struct Node{ int x, y; do
阅读全文