#include <vector>
#include <iostream>
#include <algorithm>
#define DELETED -1
#define WHITE 0
#define GREY 1
#define BLACK 2
#define RED 3
#define BLUE 4
#define MAX_INT 2147483647
using namespace std;
// The structure, describing the roads/trails
struct Route {
int color;
unsigned int to;
unsigned int length;
// Constructor by destination, length and color of edge
Route(unsigned int to, unsigned int length, int color) {
this->to = to;
this->color = color;
this->length = length;
}
};
/*
Function implements ordinary Dijkstra's algorithm (for all edges of the same color)
As a result, an array of distances filled with the minimum distance to each vertex
*/
void djikstra(vector<Route>* graph, int* distancesInColoredGraph, unsigned int quantityOfAllVertices, int finishVertex, int color) {
int vertexWithMinDist = -1;
bool* passed = new bool[quantityOfAllVertices];
fill(passed, passed + quantityOfAllVertices, false);
fill(distancesInColoredGraph, distancesInColoredGraph + quantityOfAllVertices, MAX_INT);
distancesInColoredGraph[finishVertex] = 0;
for (unsigned int indexOfCurrentVertex = 0; vertexWithMinDist == -1 || indexOfCurrentVertex < quantityOfAllVertices && distancesInColoredGraph[vertexWithMinDist] != MAX_INT; indexOfCurrentVertex++) {
vertexWithMinDist = -1;
for (unsigned int indexOfVertex = 0; indexOfVertex < quantityOfAllVertices; indexOfVertex++) {
if (!passed[indexOfVertex] && (vertexWithMinDist == -1 || distancesInColoredGraph[indexOfVertex] < distancesInColoredGraph[vertexWithMinDist])) {
vertexWithMinDist = indexOfVertex;
}
}
passed[vertexWithMinDist] = true;
for (unsigned int adjacentVertex = 0; adjacentVertex < graph[vertexWithMinDist].size(); adjacentVertex++) {
if (graph[vertexWithMinDist][adjacentVertex].color == color
&& graph[vertexWithMinDist][adjacentVertex].length + distancesInColoredGraph[vertexWithMinDist] < distancesInColoredGraph[graph[vertexWithMinDist][adjacentVertex].to]) {
distancesInColoredGraph[graph[vertexWithMinDist][adjacentVertex].to] = graph[vertexWithMinDist][adjacentVertex].length + distancesInColoredGraph[vertexWithMinDist];
}
}
}
}
// Function indicates the edges we don't need as deleted (because we can't pass them)
void simplify(vector<Route>* graph, int* distance, unsigned int quantityOfAllVertices, int color) {
// Note as DELETED routes in which the minimum distance to finish vertex increases, cause we can't walk them on the strength of problem's condition
for (unsigned int indexOfCurrentVertex = 0; indexOfCurrentVertex < quantityOfAllVertices; indexOfCurrentVertex++) {
for (unsigned int adjacentVertex = 0; adjacentVertex < graph[indexOfCurrentVertex].size(); adjacentVertex++) {
if (graph[indexOfCurrentVertex][adjacentVertex].color == color
&& distance[indexOfCurrentVertex] <= distance[graph[indexOfCurrentVertex][adjacentVertex].to]) {
graph[indexOfCurrentVertex][adjacentVertex].color = DELETED;
}
}
}
}
// Function determines whether you can go in cycle by the edges of alternating colors
bool cyclicDFS(vector<Route>* graph, int* passedInRedGraph, int* passedInBlueGraph, int currentVertex, int color) {
bool answer = false;
// Note processing vertex
if (color == RED) {
passedInRedGraph[currentVertex] = GREY;
} else {
passedInBlueGraph[currentVertex] = GREY;
}
/*
Implement ordinary checking on cycle, by coloring graph
Treat until we don't determine it is acyclic or try to color vertex that is already colored
We should take into account the fact, that each time we alternate the color of the edges
*/
for (unsigned int adjacentVertex = 0; adjacentVertex < graph[currentVertex].size() && !answer; adjacentVertex++) {
if (graph[currentVertex][adjacentVertex].color == color) {
if (color == BLUE && passedInRedGraph[graph[currentVertex][adjacentVertex].to] == GREY
|| color == RED && passedInBlueGraph[graph[currentVertex][adjacentVertex].to] == GREY) {
answer = true;
}
if (color == RED && passedInBlueGraph[graph[currentVertex][adjacentVertex].to] == WHITE) {
if (cyclicDFS(graph, passedInRedGraph, passedInBlueGraph, graph[currentVertex][adjacentVertex].to, BLUE)) {
answer = true;
}
} else if (passedInRedGraph[graph[currentVertex][adjacentVertex].to] == WHITE) {
if (cyclicDFS(graph, passedInRedGraph, passedInBlueGraph, graph[currentVertex][adjacentVertex].to, RED)) {
answer = true;
}
}
}
}
// Note processed vertex
if (color == RED) {
passedInRedGraph[currentVertex] = BLACK;
} else {
passedInBlueGraph[currentVertex] = BLACK;
}
return answer;
}
// Function determines whether there is a suitable cycle in the graph
bool isCyclic(vector<Route>* graph, unsigned int quantityOfAllVertices, int currentVertex) {
int* passedInRedGraph = new int[quantityOfAllVertices];
int* passedInBlueGraph = new int[quantityOfAllVertices];
fill(passedInRedGraph, passedInRedGraph + quantityOfAllVertices, WHITE);
fill(passedInBlueGraph, passedInBlueGraph + quantityOfAllVertices, WHITE);
return cyclicDFS(graph, passedInRedGraph, passedInBlueGraph, currentVertex, RED);
}
// Function determines the longest path in the graph by the edges of alternating colors, by finding and memorizing the maximum path to each of the vertices
int maxDistDFS(vector<Route>* graph, int* maxDistancesInRedGraph, int* maxDistancesInBlueGraph, int currentVertex, int color) {
// Return the length of the path from the current vertex, if it's found already
if (color == RED && maxDistancesInRedGraph[currentVertex] != -1) {
return maxDistancesInRedGraph[currentVertex];
}
if (color == BLUE && maxDistancesInBlueGraph[currentVertex] != -1) {
return maxDistancesInBlueGraph[currentVertex];
}
int maxDistance = -1; // Initially, we consider the longest path by any negative number
for (unsigned int adjacentVertex = 0; adjacentVertex < graph[currentVertex].size(); adjacentVertex++) {
/*
Recursively find the longest path to the finish vertex
We should take into account the fact, that each time we alternate the color of the edges
*/
if (graph[currentVertex][adjacentVertex].color == color) {
int currentMaxDistance = maxDistDFS(graph, maxDistancesInRedGraph, maxDistancesInBlueGraph, graph[currentVertex][adjacentVertex].to,
color == RED ? BLUE : RED) + graph[currentVertex][adjacentVertex].length;
maxDistance = max(maxDistance, currentMaxDistance);
}
}
// Remember the results received in the process of bypassing for later use
if (color == RED) {
maxDistancesInRedGraph[currentVertex] = maxDistance;
} else {
maxDistancesInBlueGraph[currentVertex] = maxDistance;
}
return maxDistance;
}
// Function returns the longest path in the graph from the start vertex to the finish
int getMaxDist(vector<Route>* graph, unsigned int quantityOfAllVertices, int startVertex, int finishVertex) {
int* maxDistancesInRedGraph = new int[quantityOfAllVertices];
int* maxDistancesInBlueGraph = new int[quantityOfAllVertices];
fill(maxDistancesInRedGraph, maxDistancesInRedGraph + quantityOfAllVertices, -1);
fill(maxDistancesInBlueGraph, maxDistancesInBlueGraph + quantityOfAllVertices, -1);
maxDistancesInRedGraph[finishVertex] = 0;
maxDistancesInBlueGraph[finishVertex] = 0;
return maxDistDFS(graph, maxDistancesInRedGraph, maxDistancesInBlueGraph, startVertex, RED);
}
int main() {
ios::sync_with_stdio(false);
unsigned int quantityOfAllVertices, quantityOfVertices, startVertex, finishVertex, from, to, length;
cin >> quantityOfAllVertices >> startVertex >> finishVertex;
startVertex--; finishVertex--; // Shift numbering
vector<Route>* graph = new vector<Route>[quantityOfAllVertices]; // Stores graph as array of routes for each vertex
cin >> quantityOfVertices;
while (quantityOfVertices--) {
cin >> from >> to >> length;
from--; to--; // Shift numbering
if (from != to) { // Don't read cycles
// Initially, all roads are bidirectional, add symmetrically
graph[from].push_back(Route(to, length, RED));
graph[to].push_back(Route(from, length, RED));
}
}
cin >> quantityOfVertices;
while (quantityOfVertices--) {
cin >> from >> to >> length;
from--; to--;
if (from != to) {
graph[from].push_back(Route(to, length, BLUE));
graph[to].push_back(Route(from, length, BLUE));
}
}
int* distancesInRedGraph = new int[quantityOfAllVertices]; // Shortest distances from each vertex to the final by red edges
int* distancesInBlueGraph = new int[quantityOfAllVertices]; // Shortest distances from each vertex to the final by blue edges
djikstra(graph, distancesInRedGraph, quantityOfAllVertices, finishVertex, RED); // Find and remember the shortest path by the red edges
djikstra(graph, distancesInBlueGraph, quantityOfAllVertices, finishVertex, BLUE); // Find and remember the shortest path by the blue edges
simplify(graph, distancesInRedGraph, quantityOfAllVertices, RED); // Note red edges which we can't pass, so that later they don't take into account
simplify(graph, distancesInBlueGraph, quantityOfAllVertices, BLUE); // Note blue edges which we can't pass, so that later they don't take into account
cout << (isCyclic(graph, quantityOfAllVertices, startVertex) ? -1 : getMaxDist(graph, quantityOfAllVertices, startVertex, finishVertex)) << endl;
return 0;
}