题目:
在世界的某个地方(具体记不清了,好像是北极附近)有一些岛(Vertices)和岛之间的桥(Edges)。因为气温太低,有些桥比较人性化,桥面安装了加热设备(HOT BRIDGES),但为了省钱(或是其他原因,记不清了)不是所有桥都装有加热设备 (COLD BRIDGES)。假设一个人从某个岛(Source)通过一些桥去往另一个岛(Destination),求满足以下条件的最短路径(Djistra)是否存在:
1. 该人必须交替使用COLD和HOT的桥,即如果上一个走到桥是HOT,下一个走的必须是COLD,vice versa (理由是连续走两个COLD会冻死,连续走两个HOT会热死)。
2. 两个岛之间可能会有两座桥,一座HOT,一座COLD。
3. 桥是单向的(有向边)。
程序有如下一些约束条件:
1. 输入是STDIN,输出是STDOUT。
2. 桥的个数和岛的格式在Int表示范围内
3. 输入格式如下:
2
2 1 0 1
0 1 HOT
2 1 0 1
0 1 COLD
其中第一行的“2”表示程序有两个测试用例。 接下来的 2 1 0 1 表示2个顶点,1条边,起点为0号顶点,终点为1号顶点。接下来的 0 1 HOT为边的描述:从0到1的一条HOT边。接下来的2 1 0 1是第二个测试用例,定义如上。
思路:变种Dijkstra算法,需要为每个岛(顶点)保存两个distances,一个为通过HOT到达此岛的distance,一个为通过COLD到达的distance。同样的,也需要两个排序set来对COLD和HOT排序。
题解:
#include <iostream> #include <map> #include <list> #include <set> #include <limits> #include <string> using namespace std; typedef int vertex_t; typedef bool status_t; struct edge { vertex_t target; status_t status; edge(vertex_t v, status_t s):target(v),status(s){} }; template <typename T1, typename T2> struct comparator { bool operator()( pair<T1, T2> p1, pair<T1, T2> p2) { return p1.first < p2.first; } }; //The comparator used for sorting the edge weights. typedef map<vertex_t, list<edge>> adjacentList; // Store the minimum distances from source to each intermediate nodes and the destination. typedef map<vertex_t, int> minDistance; typedef set<pair<int, vertex_t>, comparator<int, vertex_t>> sortedEdges; void buildGraph(map<vertex_t, list<edge>> & graph, int & s, int & e, int & nodes) { int numOfNodes, numOfEdges, start, end; cin >> numOfNodes >> numOfEdges >> start >> end; nodes = numOfNodes; s = start; e = end; for( int i = 0; i < numOfEdges; i++) { vertex_t first, second; status_t status; char temp[10]; cin >> first >> second >> temp; if(temp == "COLD") status = false; else if(temp == "HOT") status = true; graph[first].push_back(edge(second, status)); } } void shortestPath(vertex_t source, adjacentList & graph, minDistance & distancesHot, minDistance & distancesCold) { sortedEdges edgeSetHot, edgeSetCold; for(map<vertex_t, list<edge>>::iterator iter = graph.begin(); iter != graph.end(); iter++) { pair<int, vertex_t> wrapper(distancesHot[iter->first], iter->first); edgeSetHot.insert(wrapper); } for(map<vertex_t, list<edge>>::iterator iter = graph.begin(); iter != graph.end(); iter++) { pair<int, vertex_t> wrapper(distancesCold[iter->first], iter->first); edgeSetCold.insert(wrapper); } while(!edgeSetHot.empty() && !edgeSetCold.empty()) { vertex_t current; if(edgeSetHot.begin()->first < edgeSetCold.begin()->first) { current = edgeSetHot.begin()->second; edgeSetHot.erase(edgeSetHot.begin()); } else { current = edgeSetCold.begin()->second; edgeSetCold.erase(edgeSetCold.begin()); } for(list<edge>::iterator iter = graph[current].begin(); iter != graph[current].end(); iter++) { vertex_t neighbor = iter->target; int distanceThroughCurrent; if(iter->status) {//Hot distanceThroughCurrent = distancesCold[current] + 1; if(distanceThroughCurrent < distancesHot[neighbor]) { pair<int, vertex_t> wrapper(distancesHot[neighbor], neighbor); edgeSetCold.erase(wrapper); distancesHot[neighbor] = distanceThroughCurrent; wrapper.first = distancesHot[neighbor]; edgeSetHot.insert(wrapper); } } else { distanceThroughCurrent = distancesHot[current] + 1; if(distanceThroughCurrent < distancesCold[neighbor]) { pair<int, vertex_t> wrapper(distancesCold[neighbor], neighbor); edgeSetHot.erase(wrapper); distancesCold[neighbor] = distanceThroughCurrent; wrapper.first = distancesCold[neighbor]; edgeSetCold.insert(wrapper); } } } } return; } int main() { /* Enter your code here. Read input from STDIN. Print output to STDOUT */ int numberOfTestCases = 0; cin >> numberOfTestCases; if(numberOfTestCases) { for(int i = 0; i < numberOfTestCases; i++) { adjacentList graph; int start, end, nodes; buildGraph(graph, start, end, nodes); minDistance distancesHot, distancesCold; for(int i = 0; i < nodes; i++) { distancesHot[i] = numeric_limits<int>::max(); distancesCold[i] = numeric_limits<int>::max(); } distancesHot[start] = 0; distancesCold[start] = 0; shortestPath(start, graph, distancesHot, distancesCold); int min = numeric_limits<int>::max(); if(distancesCold[end] < min) min = distancesCold[end]; if(distancesHot[end] < min) min = distancesHot[end]; if(min == numeric_limits<int>::max()) min = -1; cout << min << endl; } } return 0; }