奇妙旅行
描述
小熊住在由n个城镇(城镇编号from 1 to n)组成的国家里,n-1条双向联通的路将这n个城镇相互连接。所以从一个城镇旅行到其他任意一个城镇都是可行的。小熊想要进行一次旅行,它选择一对城镇(u,v)(u ≠ v),然后选择从u到v的最短路径完成旅行。(注意:(u,v)和(v,u)被认为是不同旅行。)
然而,在小熊的国家里,有2个特殊的城镇,一个叫伦敦(编号x),一个叫巴黎(编号y)。伦敦是一个被花香萦绕的小镇,巴黎是一个到处都是蜜蜂的小镇。因此,小熊在旅行过程中,如果先经过伦敦,再经过巴黎,他就会遭到蜜蜂的疯狂攻击。
请你帮帮小熊计算出有多少对(u,v)可供选择来完成旅行计划。
输入描述
第一行包含3个整数,n,x,y(1 ≤n≤3000, 1≤x,y≤n , x ≠ y) ,n表示城镇数量,x表示伦敦的编号,y表示巴黎的编号。
接下来n-1行,每行包括两个整数a,b(1≤a,b≤n1≤a,b≤n, a≠b),描述了城镇a和城镇b之间存在一条道路。
输入保证,任意两点都彼此联通(所给的城镇和道路组成了一棵树)。
输出描述
输出有多少对(u,v)可供小熊选择来完成旅行。
样例输入 1
3 1 3
1 2
2 3
样例输出 1
5
样例输入 2
3 1 3
1 2
1 3
样例输出 2
4
提示
第一个example中,小熊有5种选择
(1,2): 他的路线是 1→2
(2,3): 他的路线是 2→3
(3,2): 他的路线是 3→2
(2,1): 他的路线是 2→1
(3,1): 他的路线是 3→2→1
小熊不能选择(1,3)。因为如果它选择这个路线,他会先访问城镇1(伦敦)再访问城镇3(巴黎),它会遭到蜜蜂的攻击,这会让小熊受伤。
// WonderfulTrip.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <string> // to_string(), C++ 11
#include <climits> // INT_MAX
#include <algorithm> // min()
using namespace std;
// #define UNIT_TEST
// #define PRINT_PATH_INFO
// save the shortest Distance information from starting vertex to each vertex
struct Distance
{
string pathInfo;
vector<int> pathVec;
int value;
bool visited;
Distance()
{
visited = false;
value = 0;
pathInfo = "";
}
};
class Graph_DG
{
private:
static const int max_weight = numeric_limits<int>::max(); // INT_MAX
int m_vertexLondon;
int m_vertexParis;
int m_numOfVertexs; // number of vertexs
int m_numOfEdges; // number of edges
int **m_adjaMatrix; // adjacent Matrix
Distance *m_dist; // distance
set<int> m_vertexInSet;
set<int> m_vertexOutSet;
bool checkValuesScope(int vertexIn, int vertexOut, int weight);
void generateGraphDat();
void createGraph();
void Dijkstra(int vertexIn);
void reinitDistance();
int getNumOfPathsOfOneVertex(int vertexIn);
public:
~Graph_DG();
int getTotalNumOfPaths();
};
Graph_DG::~Graph_DG()
{
delete [] m_dist;
for (int i = 0; i < this->m_numOfVertexs; i++)
{
delete this->m_adjaMatrix[i];
}
delete m_adjaMatrix;
}
void Graph_DG::generateGraphDat()
{
int vertexIn, vertexOut;
vector<int> vertexs;
cin >> m_numOfVertexs >> m_vertexLondon >> m_vertexParis;
m_numOfEdges = 0;
for (int i = 1; i <= m_numOfVertexs - 1; i++)
{
cin >> vertexIn >> vertexOut;
vertexs.push_back(vertexIn);
vertexs.push_back(vertexOut);
m_numOfEdges += 2;
}
ofstream out;
out.open("graph.dat");
out << m_numOfVertexs << " " << m_numOfEdges << endl;
for (unsigned int i = 0; i < vertexs.size() - 1; i += 2)
{
out << vertexs[i] << " " << vertexs[i + 1] << " " << 1 << endl;
out << vertexs[i + 1] << " " << vertexs[i] << " " << 1 << endl;
}
out.close();
}
bool Graph_DG::checkValuesScope(int vertexIn, int vertexOut, int weight)
{
if (vertexIn < 1 || vertexOut < 1 || vertexIn > m_numOfVertexs ||
vertexOut > m_numOfVertexs || weight < 0)
{
return false;
}
return true;
}
void Graph_DG::reinitDistance()
{
delete [] m_dist;
m_dist = new Distance [this->m_numOfVertexs];
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_dist[i].value = 0;
}
}
void Graph_DG::createGraph()
{
int vertexIn;
int vertexOut;
int weight;
ifstream ifp("graph.dat");
ifp >> this->m_numOfVertexs >> this->m_numOfEdges;
// allocate space for m_adjaMatrix and m_dist
m_adjaMatrix = new int*[this->m_numOfVertexs];
m_dist = new Distance[this->m_numOfVertexs];
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_adjaMatrix[i] = new int[this->m_numOfVertexs];
for (int k = 0; k < this->m_numOfVertexs; k++)
{
// initialize each element of adjacent matrix
m_adjaMatrix[i][k] = max_weight;
}
}
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_adjaMatrix[i][i] = 0;
m_dist[i].value = 0;
}
for (int i = 0; i < this->m_numOfEdges; i++)
{
ifp >> vertexIn >> vertexOut >> weight;
if (true == checkValuesScope(vertexIn, vertexOut, weight))
{
m_vertexInSet.insert(vertexIn);
m_vertexOutSet.insert(vertexOut);
#ifdef UNIT_TEST
cout << "V" << vertexIn << " -- " << weight << " --> V" << vertexOut << endl;
#endif
// assign weight value for vertexIn to vertexOut
m_adjaMatrix[vertexIn - 1][vertexOut - 1] = weight;
}
}
ifp.close();
}
void Graph_DG::Dijkstra(int vertexIn)
{
// Firstly, initialize distance array
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
// set the current pathInfo
m_dist[vertexIdx].pathInfo = "V" + to_string(vertexIn)
+ " --> V" + to_string(vertexIdx + 1);
m_dist[vertexIdx].value = m_adjaMatrix[vertexIn - 1][vertexIdx];
m_dist[vertexIdx].pathVec.push_back(vertexIn);
m_dist[vertexIdx].pathVec.push_back(vertexIdx + 1);
}
// calculate the shortest distance from vertex to other vertexs
for (int m_numOfVertexs = 1; m_numOfVertexs < this->m_numOfVertexs; m_numOfVertexs++)
{
int tmpVertex = 0; // save the minimum vertex index in array m_dist[]
int min_value = max_weight; // save the minimum value
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
if (!m_dist[vertexIdx].visited && m_dist[vertexIdx].value < min_value)
{
min_value = m_dist[vertexIdx].value;
tmpVertex = vertexIdx;
}
}
// add tmpVertex to shortest distance pathInfo information
m_dist[tmpVertex].visited = true;
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
// the condition m_adjaMatrix[tmpVertex][i]!=max_weigh is required
if (!m_dist[vertexIdx].visited && m_adjaMatrix[tmpVertex][vertexIdx]!=max_weight &&
(m_dist[tmpVertex].value+m_adjaMatrix[tmpVertex][vertexIdx])<m_dist[vertexIdx].value)
{
// if new edge could impact other vertexs which are not visited, update its
// distance pathInfo information
m_dist[vertexIdx].value = m_dist[tmpVertex].value + m_adjaMatrix[tmpVertex][vertexIdx];
m_dist[vertexIdx].pathInfo = m_dist[tmpVertex].pathInfo+" --> V"+to_string(vertexIdx+1);
m_dist[vertexIdx].pathVec = m_dist[tmpVertex].pathVec;
m_dist[vertexIdx].pathVec.push_back(vertexIdx + 1);
}
}
}
}
int Graph_DG::getNumOfPathsOfOneVertex(int vertexIn)
{
Dijkstra(vertexIn);
int numOfPaths = 0;
bool foundLondonTown;
bool foundParisTown;
for (int i = 0; i != this->m_numOfVertexs; i++)
{
foundLondonTown = false;
foundParisTown = false;
if (m_dist[i].value > 0 && m_dist[i].value != max_weight)
{
int size = m_dist[i].pathVec.size();
for (int j = 0; j < size; j++)
{
if (m_dist[i].pathVec[j] == this->m_vertexLondon)
{
foundLondonTown = true;
}
else if (m_dist[i].pathVec[j] == this->m_vertexParis &&
true == foundLondonTown)
{
foundParisTown = true;
}
}
if (false == foundParisTown)
{
numOfPaths++;
#ifdef PRINT_PATH_INFO
for (int j = 0; j < size - 1; j++)
{
cout << m_dist[i].pathVec[j] << " -> ";
}
cout << m_dist[i].pathVec[size - 1] << endl;
#endif
}
}
}
return numOfPaths;
}
int Graph_DG::getTotalNumOfPaths()
{
generateGraphDat(); // generate graph.dat according to input data
createGraph(); // create directed graph according to graph.dat
int numOfPaths = 0;
for (auto vertexIn : m_vertexInSet) // C++ 11 feature
{
numOfPaths += getNumOfPathsOfOneVertex(vertexIn);
reinitDistance(); // re-initialize distance information for next time
}
return numOfPaths;
}
int main()
{
Graph_DG graph;
cout << graph.getTotalNumOfPaths() << endl;
return 0;
}
C++代码 (不生成中间文件graph.dat, 直接读取数据生成Graph)
#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <string> // to_string(), C++ 11
#include <climits> // INT_MAX
#include <algorithm> // min()
#include <cassert> // assert()
using namespace std;
// #define UNIT_TEST
// #define PRINT_PATH_INFO
// save the shortest Distance information from starting vertex to each vertex
struct Distance
{
string pathInfo;
vector<int> pathVec;
int value;
bool visited;
Distance()
{
visited = false;
value = 0;
pathInfo = "";
}
};
class Graph_DG
{
private:
static const int max_weight = numeric_limits<int>::max(); // INT_MAX
int m_vertexLondon;
int m_vertexParis;
int m_numOfVertexs; // number of vertexs
int m_numOfEdges; // number of edges
int **m_adjaMatrix; // adjacent Matrix
Distance *m_dist; // distance
set<int> m_vertexInSet;
set<int> m_vertexOutSet;
void readDataAndCreateGraph();
bool checkValuesScope(int vertexIn, int vertexOut, int weight);
void reinitDistance();
void Dijkstra(int vertexIn);
int getNumOfPathsOfOneVertex(int vertexIn);
public:
~Graph_DG();
int getTotalNumOfPaths();
};
Graph_DG::~Graph_DG()
{
delete [] m_dist;
for (int i = 0; i < this->m_numOfVertexs; i++)
{
delete this->m_adjaMatrix[i];
}
delete m_adjaMatrix;
}
bool Graph_DG::checkValuesScope(int vertexIn, int vertexOut, int weight)
{
if (vertexIn < 1 || vertexOut < 1 || vertexIn > m_numOfVertexs ||
vertexOut > m_numOfVertexs || weight < 0 || vertexIn == vertexOut)
{
return false;
}
return true;
}
void Graph_DG::reinitDistance()
{
delete [] m_dist;
m_dist = new Distance [this->m_numOfVertexs];
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_dist[i].value = 0;
}
}
void Graph_DG::readDataAndCreateGraph()
{
cin >> m_numOfVertexs >> m_vertexLondon >> m_vertexParis;
// 1 ≤n≤3000, 1≤x, y≤n, x ≠ y
assert(m_numOfVertexs >= 1 && m_numOfVertexs <= 3000);
assert(m_vertexLondon <= m_numOfVertexs && m_vertexLondon >= 1);
assert(m_vertexParis <= m_numOfVertexs && m_vertexParis >= 1);
assert(m_vertexLondon != m_vertexParis);
m_numOfEdges = 2*(m_numOfVertexs - 1);
// allocate space for m_adjaMatrix and m_dist
m_adjaMatrix = new int*[this->m_numOfVertexs];
m_dist = new Distance[this->m_numOfVertexs];
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_adjaMatrix[i] = new int[this->m_numOfVertexs];
for (int k = 0; k < this->m_numOfVertexs; k++)
{
// initialize each element of adjacent matrix
m_adjaMatrix[i][k] = max_weight;
}
}
for (int i = 0; i < this->m_numOfVertexs; i++)
{
m_adjaMatrix[i][i] = 0;
m_dist[i].value = 0;
}
int vertexIn, vertexOut, weight = 1;
for (int i = 0; i < m_numOfVertexs - 1; i++)
{
cin >> vertexIn >> vertexOut;
if (true == checkValuesScope(vertexIn, vertexOut, weight))
{
m_vertexInSet.insert(vertexIn);
m_vertexOutSet.insert(vertexOut);
#ifdef UNIT_TEST
cout << "V" << vertexIn << " -- " << weight << " --> V" << vertexOut << endl;
#endif
// assign weight value for vertexIn to vertexOut
m_adjaMatrix[vertexIn - 1][vertexOut - 1] = weight;
m_vertexInSet.insert(vertexOut);
m_vertexOutSet.insert(vertexIn);
#ifdef UNIT_TEST
cout << "V" << vertexOut << " -- " << weight << " --> V" << vertexIn << endl;
#endif
// assign weight value for vertexIn to vertexOut
m_adjaMatrix[vertexOut - 1][vertexIn - 1] = weight;
}
}
}
void Graph_DG::Dijkstra(int vertexIn)
{
// Firstly, initialize distance array
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
// set the current pathInfo
m_dist[vertexIdx].pathInfo = "V" + to_string(vertexIn)
+ " --> V" + to_string(vertexIdx + 1);
m_dist[vertexIdx].value = m_adjaMatrix[vertexIn - 1][vertexIdx];
m_dist[vertexIdx].pathVec.push_back(vertexIn);
m_dist[vertexIdx].pathVec.push_back(vertexIdx + 1);
}
// calculate the shortest distance from vertex to other vertexs
for (int m_numOfVertexs = 1; m_numOfVertexs < this->m_numOfVertexs; m_numOfVertexs++)
{
int tmpVertex = 0; // save the minimum vertex index in array m_dist[]
int min_value = max_weight; // save the minimum value
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
if (!m_dist[vertexIdx].visited && m_dist[vertexIdx].value < min_value)
{
min_value = m_dist[vertexIdx].value;
tmpVertex = vertexIdx;
}
}
// add tmpVertex to shortest distance pathInfo information
m_dist[tmpVertex].visited = true;
for (int vertexIdx = 0; vertexIdx < this->m_numOfVertexs; vertexIdx++)
{
// the condition m_adjaMatrix[tmpVertex][i]!=max_weigh is required
if (!m_dist[vertexIdx].visited && m_adjaMatrix[tmpVertex][vertexIdx]!=max_weight &&
(m_dist[tmpVertex].value+m_adjaMatrix[tmpVertex][vertexIdx])<m_dist[vertexIdx].value)
{
// if new edge could impact other vertexs which are not visited, update its
// distance pathInfo information
m_dist[vertexIdx].value = m_dist[tmpVertex].value + m_adjaMatrix[tmpVertex][vertexIdx];
m_dist[vertexIdx].pathInfo = m_dist[tmpVertex].pathInfo+" --> V"+to_string(vertexIdx+1);
m_dist[vertexIdx].pathVec = m_dist[tmpVertex].pathVec;
m_dist[vertexIdx].pathVec.push_back(vertexIdx + 1);
}
}
}
}
int Graph_DG::getNumOfPathsOfOneVertex(int vertexIn)
{
Dijkstra(vertexIn);
int numOfPaths = 0;
bool foundLondonTown;
bool foundParisTown;
for (int i = 0; i != this->m_numOfVertexs; i++)
{
foundLondonTown = false;
foundParisTown = false;
if (m_dist[i].value > 0 && m_dist[i].value != max_weight)
{
int size = m_dist[i].pathVec.size();
for (int j = 0; j < size; j++)
{
if (m_dist[i].pathVec[j] == this->m_vertexLondon)
{
foundLondonTown = true;
}
else if (m_dist[i].pathVec[j] == this->m_vertexParis &&
true == foundLondonTown)
{
foundParisTown = true;
}
}
if (false == foundParisTown)
{
numOfPaths++;
#ifdef PRINT_PATH_INFO
cout << "("<<vertexIn<<","<<m_dist[i].pathVec[size-1] << ") : ";
for (int j = 0; j < size - 1; j++)
{
cout << m_dist[i].pathVec[j] << " -> ";
}
cout << m_dist[i].pathVec[size - 1] << endl;
#endif
}
}
}
return numOfPaths;
}
int Graph_DG::getTotalNumOfPaths()
{
readDataAndCreateGraph();
int numOfPaths = 0;
for (auto vertexIn : m_vertexInSet) // C++ 11 feature
{
numOfPaths += getNumOfPathsOfOneVertex(vertexIn);
reinitDistance(); // re-initialize distance information for next time
}
return numOfPaths;
}
int main()
{
Graph_DG graph;
cout << graph.getTotalNumOfPaths() << endl;
return 0;
}