奇妙旅行

描述

小熊住在由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(巴黎),它会遭到蜜蜂的攻击,这会让小熊受伤。

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <iterator>
#include <climits>    // INT_MAX
#include <algorithm>  // min()
#include <iomanip>    // setw()

using namespace std;

// #define UNIT_TEST 
// #define PRINT_PATH_INFO 

// save the shortest Distance information from starting vertex to each vertex 
struct Distance
{
    string path;
    vector<int> pathInfo;
    int    value;
    bool   visit;
    Distance()
    {
        visit = false;
        value = 0;
        path  = "";
    }
};

class Graph_DG
{
private:
    static const int max_weight = numeric_limits<int>::max();  // INT_MAX;
    int      m_vertexLondon;
    int      m_vertexParis;
    int      m_vertexNum;
    int      m_edgeNum;
    int    **m_adjacentMatrix;
    Distance *m_distance;

    string   convertInt2String(int n);
    bool     check_edgeNum_value(int vertexIn, int vertexOut, int weight);

    set<int> m_vertexInSet;
    set<int> m_vertexOutSet;

    void generateGraphDat();
    void createGraph();
    void Dijkstra(int vertex);
    void reinitDistance();

    void printAdjacentMatrix();
    void printPathInfo(int vertexIn) {};

    int getNumOfPathsOfOneVertex(int vertex);

public:
    Graph_DG() {};
    ~Graph_DG();

    int getTotalNumOfPaths();
};

Graph_DG::~Graph_DG()
{
    delete[] m_distance;
    for (int i = 0; i < this->m_vertexNum; i++)
    {
        delete this->m_adjacentMatrix[i];
    }
    delete m_adjacentMatrix;
}

void Graph_DG::generateGraphDat()
{
    int m_vertexNum;
    int m_edgeNum = 0;
    int vertexIn, vertexOut;
    vector<int> vertexs;

    cin >> m_vertexNum >> this->m_vertexLondon >> this->m_vertexParis;

    for (int i = 1; i <= m_vertexNum - 1; i++)
    {
        cin >> vertexIn >> vertexOut;
        vertexs.push_back(vertexIn);
        vertexs.push_back(vertexOut);
        m_edgeNum += 2;
    }

    ofstream out;
    out.open("graph.dat");
    out << m_vertexNum << " " << m_edgeNum << 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::check_edgeNum_value(int vertexIn, int vertexOut, int weight)
{
    if (vertexIn < 1 || vertexOut < 1 || vertexIn > m_vertexNum ||
        vertexOut > m_vertexNum || weight < 0)
    {
        return false;
    }
    return true;
}

void Graph_DG::reinitDistance()
{
    delete[] m_distance;

    m_distance = new Distance[this->m_vertexNum];
    for (int i = 0; i < this->m_vertexNum; i++)
    {
        m_distance[i].value = 0;
    }
}

void Graph_DG::createGraph()
{
    int vertexIn;
    int vertexOut;
    int weight;

    ifstream ifp("graph.dat");
    ifp >> this->m_vertexNum >> this->m_edgeNum;

    // allocate space for m_adjacentMatrix and m_distance 
    m_adjacentMatrix = new int*[this->m_vertexNum];
    m_distance = new Distance[this->m_vertexNum];

    for (int i = 0; i < this->m_vertexNum; i++)
    {
        m_adjacentMatrix[i] = new int[this->m_vertexNum];
        for (int k = 0; k < this->m_vertexNum; k++)
        {
            // initialize each element of adjacent matrix 
            m_adjacentMatrix[i][k] = max_weight;
        }
    }

    for (int i = 0; i < this->m_vertexNum; i++)
    {
        m_adjacentMatrix[i][i] = 0;
        m_distance[i].value    = 0;
    }

    for (int i = 0; i < this->m_edgeNum; i++)
    {
        ifp >> 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_adjacentMatrix[vertexIn - 1][vertexOut - 1] = weight;

        // add the following line for undirected graph 
        // m_adjacentMatrix[vertexOut-1][vertexIn-1] = weight;
    }
    ifp.close();
}

void Graph_DG::printAdjacentMatrix()
{
    cout << "Graph's adjacent matrix is " << endl;
    int row = 0;
    int col = 0;

    // start to print adjacent matrix
    for (int row = 0; row < this->m_vertexNum; row++)
    {
        for (int col = 0; col < this->m_vertexNum; col++)
        {
            if (max_weight == m_adjacentMatrix[row][col])
            {
                cout << "∞" << " ";
            }
            else
            {
                cout << setw(2) << m_adjacentMatrix[row][col] << " ";
            }
        }
        cout << endl;
    }
}

string Graph_DG::convertInt2String(int n)
{
    string s;
    stringstream os;
    os << n;
    os >> s;
    return s;
}

void Graph_DG::Dijkstra(int vertex)
{
    // Firstly, initialize distance array 
    for (int vertexIdx = 0; vertexIdx < this->m_vertexNum; vertexIdx++)
    {
        // set the current path
        m_distance[vertexIdx].path = "V" + convertInt2String(vertex)
			+ " --> V" + convertInt2String(vertexIdx + 1);
        m_distance[vertexIdx].value = m_adjacentMatrix[vertex - 1][vertexIdx];
        m_distance[vertexIdx].pathInfo.push_back(vertex);
        m_distance[vertexIdx].pathInfo.push_back(vertexIdx + 1);
    }

    // calculate the shortest distance from vertex to other vertex (this->m_vertexNum-1)
    for (int m_vertexNum = 1; m_vertexNum < this->m_vertexNum; m_vertexNum++)
    {
        int tmpVertex = 0;  // save the minimum vertex index in array m_distance[]
        int min_value = max_weight; // save the minimum value
        for (int vertexIdx = 0; vertexIdx < this->m_vertexNum; vertexIdx++)
        {
            if (!m_distance[vertexIdx].visit && m_distance[vertexIdx].value < min_value)
            {
                min_value = m_distance[vertexIdx].value;
                tmpVertex = vertexIdx;
            }
        }

        // add tmpVertex to shortest distance path information
        m_distance[tmpVertex].visit = true;

        for (int vertexIdx = 0; vertexIdx < this->m_vertexNum; vertexIdx++)
        {
            // the condition m_adjacentMatrix[tmpVertex][i]!=max_weigh is required
            if (!m_distance[vertexIdx].visit && m_adjacentMatrix[tmpVertex][vertexIdx] != max_weight &&
                (m_distance[tmpVertex].value + m_adjacentMatrix[tmpVertex][vertexIdx]) < m_distance[vertexIdx].value)
            {
                //if new edge could impact other vertexs which are not visited, update its distance path information
                m_distance[vertexIdx].value = m_distance[tmpVertex].value + m_adjacentMatrix[tmpVertex][vertexIdx];
                m_distance[vertexIdx].path  = m_distance[tmpVertex].path + " --> V" + convertInt2String(vertexIdx + 1);
                m_distance[vertexIdx].pathInfo = m_distance[tmpVertex].pathInfo;
                m_distance[vertexIdx].pathInfo.push_back(vertexIdx + 1);
            }
        }
    }
}

int Graph_DG::getNumOfPathsOfOneVertex(int vertex)
{
    int  numOfPaths = 0;
    bool foundLondonTown;
    bool foundParisTown;

    for (int i = 0; i != this->m_vertexNum; i++)
    {
        foundLondonTown = false;
        foundParisTown  = false;

        if (m_distance[i].value > 0 && m_distance[i].value != max_weight)
        {
            int size = m_distance[i].pathInfo.size();

            for(int j=0; j<size; j++)
            {
                if (m_distance[i].pathInfo[j] == this->m_vertexLondon)
                {
                    foundLondonTown = true;
                }
                else if (m_distance[i].pathInfo[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_distance[i].pathInfo[j] << " -> ";
                }
                cout << m_distance[i].pathInfo[size-1] << endl;
#endif
            }
        }
    }
    return numOfPaths;
}

int Graph_DG::getTotalNumOfPaths()
{
    generateGraphDat();  // input data 

    createGraph();

    set<int>::iterator iter;
    int numOfPaths = 0;
    for (iter = m_vertexInSet.begin(); iter != m_vertexInSet.end(); iter++)
    {
        Dijkstra(*iter);

        numOfPaths += getNumOfPathsOfOneVertex(*iter);

        reinitDistance();  // re-initialize distance information
    }

    return numOfPaths;
}

int main()
{
    Graph_DG graph;

    cout << graph.getTotalNumOfPaths() << endl;

    return 0;
}


11-04 01:53