一道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
解题思路:如果只是最小,那么单元最短路径就可以解决,但是还要有最长,所以就不能这么做了。
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 0x80000000
struct 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;
}