圣诞岛的旅行

来源:互联网 发布:常用的网络传输介质有 编辑:程序博客网 时间:2024/05/04 21:44

一道ACM上的题,无聊的时候写写。

圣诞岛的旅行

Problem
Angel最近无聊,去了圣诞岛(CX *^_^*),他喜欢无目的的乱逛,当然,他不会轻易地回头。Angel想去广场,那么,他什么时候才能到呢?你已经得到了CX的地图,地图上有N(N <= 100)个交叉路口,交叉路口之间有马路相连接(不超过1000条马路)。因为CX的人遵循奇怪的规则,道路都是单向的,不同的道路之间有一定的距离,我们假设Angel所在的地点为点1,广场所在点为N。假设Angel走一单位距离需要一单位时间。问Angel最早和最迟什么时候到达广场? 

Input
本题有多组数据,第一行N, M,M是边的数量以后M行,每行3个整数X, Y, Weight,代表一条从X城市到Y城市,长度为Wweight的边。 

Output
每组数据,第一行是最少时间,第二行是最迟时间,要是可怜的Angel可能永远到不了广场,输出一行Never。 

Sample Input
5 5
1 2 1
1 4 10
2 3 1
3 4 1
4 5 1

Sample Output
4
11
解题思路:如果只是最小,那么单元最短路径就可以解决,但是还要有最长,所以就不能这么做了。

一般的思路是先拓补排序,然后将该序列进行DP求解。

拓补排序可以看这里:拓补排序

然后DP的子结构为:

从u 到 v 的最长路径/最短路径 = MAX/MIN( length(u,i) + length(i,v)) 其中 i是拓补序列中位于u和v之间的点。

//filename: MerryIsland.h#pragma once#include <stdio.h>#include <stack>//using namespace std;#define WHITE 0#define BLACK 2#define GRAY 1#define MAX 0x7fffffff#define MIN 0x80000000struct status{int v;int index;};int dfsWithoutRecursion(int** graph, int numV, int origin, int* pointColor, int* tpArray){int tpIndex = numV-1;std::stack<status> st;status sOrigin;sOrigin.v = origin;sOrigin.index = 0;st.push(sOrigin);while (!st.empty()){status sV = st.top();st.pop();int i;for (i = sV.index; i < numV; i++){if (graph[sV.v][i]){if (pointColor[i] == WHITE){sV.index = i + 1;status detectedV;detectedV.v = i;detectedV.index = 0;st.push(sV);st.push(detectedV);pointColor[i] = GRAY;break;}else if (pointColor[i] == GRAY)return -1;}}if (i == numV){pointColor[sV.v] = BLACK;tpArray[tpIndex--] = sV.v;}}return 0;}int dfs(int **graph, int numV, int* tpArray){int *pointColor = new int[numV];memset(pointColor, WHITE, numV * sizeof(int));printf("start from 0.\r\n");pointColor[0] = GRAY;int result = dfsWithoutRecursion(graph, numV, 0, pointColor, tpArray);delete pointColor;return result;}//拓补排序//graph: 图的数据[in]//tpArray: 拓补序列[out]//num: 结点数量[in]int topologicalSort(int** graph, int* tpArray, int num){return dfs(graph, num, tpArray);}struct Cell{int min = MAX;int max = MIN;};//graph: 图的数据[in]//tpArray: 拓补序列[in]//num: 结点数量[in]int merryIsland(int** graph, int* tpArray, int num){//初始化记忆矩阵Cell** distance = new Cell*[num];for (int i = 0; i < num; i++){distance[i] = new Cell[num];}for (int j = 1; j < num; j++){for (int i = 0; i + j < num; i++){if (distance[i][i + j].min == MAX){if (graph[tpArray[i]][tpArray[i + j]]){distance[i][i + j].min = graph[tpArray[i]][tpArray[i + j]];}}if (distance[i][i + j].max == MIN){if (graph[tpArray[i]][tpArray[i + j]]){distance[i][i + j].max = graph[tpArray[i]][tpArray[i + j]];}}for (int k = 1; k < i + j; k++){if (distance[i][k].min != MAX && distance[k][i + j].min != MAX){int min = distance[i][k].min + distance[k][i + j].min;if (distance[i][i + j].min > min){distance[i][i + j].min = min;}}if (distance[i][k].max != MIN && distance[k][i + j].max != MIN){int max = distance[i][k].max + distance[k][i + j].max;if (distance[i][i + j].max < max){distance[i][i + j].max = max;}}}}}for (int j = 1; j < num; j++){for (int i = 0; i + j < num; i++){printf("[%d-%d]:min-%d;max-%d.\r\n", tpArray[i],tpArray[i + j], distance[i][i + j].min, distance[i][i + j].max);}}printf("%d\r\n%d\r\n", distance[tpArray[0]][tpArray[num - 1]].min, distance[tpArray[0]][tpArray[num - 1]].max);return 0;}int entry(int** graph, int* tpArray, int num){if (topologicalSort(graph, tpArray, num)){printf("图中存在环...end");return -1;}merryIsland(graph, tpArray, num);return 0;}

entry函数式解题主函数,先拓补排序,然后再按照拓步序列进行解题,需要注意的是拓步序列与实际图中点的对应关系

下面是主函数和相关变量的初始化

#include <stdio.h>#include <Windows.h>#include <string.h>#include "MerryIsland.h"int main(){int vn = 0;int en = 0;scanf_s("%d %d", &vn, &en);int** graph = new int*[vn];for (int i = 0; i < vn; i++){graph[i] = new int[vn];memset(graph[i], 0, sizeof(int)*vn);}for (int i = 0; i < en; i++){int s;int e;int l;scanf_s("%d %d %d", &s, &e, &l);graph[s][e] = l;}int* tpArray = new int[vn];entry(graph, tpArray, vn); for (int i = 0; i < vn; i++){printf("%d ", tpArray[i]);}system("pause");return 0;}





0 0