圣诞岛的旅行

一道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 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;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值