1 问题分析
1.1 原题目链接
1.2 解题思路
此题相当于简单有向图的最短路径问题,只是把总消耗改为路径上最高权值。
最短路算法在《数据结构》图的章节有介绍两种经典的算法:Dijkstra,Floyd-Warshall。用Floyd算法代码会更简单,且代码紧凑,并不包含复杂的数据结构,因此算法复杂度隐含的常系数很小,即使对于中等规模的输入来说,仍然相当有效(该句引自文献[1]第99页)。网上有相应代码,引用自:(CSDN ID)tao_tao_bu_jue
#include <iostream>
using namespace std;
int n,m,t;
const int inf=1000000000;
int mat[301][301];
int MAX(int a,int b){return a>b?a:b;}
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j||i==k||j==k) continue;
if(MAX(mat[i][k],mat[k][j])<mat[i][j])
mat[i][j]=MAX(mat[i][k],mat[k][j]);
}
}
int main()
{
int i,j,s,e,len;
while(scanf("%d%d%d",&n,&m,&t)!=EOF){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
mat[i][j]=inf;
while(m--)
{
scanf("%d%d%d",&s,&e,&len);
mat[s][e]=len;
}
floyd();
while(t--)
{
scanf("%d%d",&s,&e);
printf("%d\n",mat[s][e]==inf?-1:mat[s][e]);
}
}
}
此处我用Dijkstra方法求解,并使用(前向)星形表示法的数据结构,代码肯定比Floyd的复杂,我主要是做效率上的测试。想了解星形表示法的读者请下载参考文献[2],图与网络那章有做详细的介绍。
2 解题代码
AC时间:2013-09-08 20:46:05
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
#define MAXN 310
#define VNUM 25010
#define Inf 1000000000
struct MsgType
{
int v1;
int v2;
int w;
bool operator< (const MsgType&rhs) const
{
if( v1 - rhs.v1 ) return v1 < rhs.v1;
else return v2 < rhs.v2;
}
};
int N,M,T;
int v1[VNUM], v2[VNUM], w[VNUM], index[MAXN];
vector<MsgType> MsgTable;
void GetData()
{
int i, val;
MsgType t;
vector<MsgType>::iterator it;
for( i = 0; i < M; i++ )
{
scanf("%d%d%d",&t.v1,&t.v2,&t.w);
MsgTable.push_back(t);
}
sort( MsgTable.begin(), MsgTable.end() );
memset( index, -1, sizeof(int)*(N+1) );
it = MsgTable.begin();
index[1] = 1;
v1[1] = (*it).v1;
v2[1] = (*it).v2;
w[1] = (*it).w;
it++;
for( i = 2; i <= M; i++, it++ )
{
if( (*it).v1 != v1[i-1] ) index[ (*it).v1 ] = i;
v1[i] = (*it).v1;
v2[i] = (*it).v2;
w[i] = (*it).w;
}
MsgTable.clear();
index[ N+1 ] = M + 1;
for(val = M + 1, i = N; i > 0; i-- )
{
if( index[i] == -1 ) index[i] = val;
else val = index[i];
}
}
void Dijkstra( int start, int end, int dist[MAXN] )
{
int i, min, tmp, p, small,logo ;
bool mark[MAXN]={0};
mark[start] = 1;
for( i = 1; i <= N; i++ ) dist[i] = Inf;
for( i = index[start], tmp = index[start+1]; i < tmp; i++ )
dist[ v2[i] ] = w[i];
while(1)
{
for(logo=1, min = Inf, i = 1; i <= N; i++ ) if( !mark[i] ) if( dist[i] < min )
{
logo = 0;
min = dist[i];
p = i;
}
if( logo ) break;
mark[p] = 1;
tmp = index[p+1];
for( i = index[p]; i < tmp; i++ ) if( !mark[ v2[i] ] )
{
small = min > w[i] ? min:w[i];
if( small < dist[ v2[i] ] )
dist[ v2[i] ] = small;
}
}
}
int main()
{
int start, end, mark[MAXN], dist[MAXN][MAXN];
while( scanf("%d%d%d",&N,&M,&T)!=EOF )
{
GetData();
memset(mark,0,sizeof(int)*MAXN);
while( T-- )
{
scanf( "%d%d", &start, &end );
if( !mark[start] )
{
mark[start] = 1;
Dijkstra(start,end,dist[start]);
}
if( dist[start][end] == Inf )
printf("-1\n");
else
printf("%d\n",dist[start][end]);
}
}
return 0;
}
3 结果分析
我把传统的Floyd代码和我用星形数据结构,Dijkstra算法的程序各提交了两次,测试结果如图3—1所示:前者时间分别为421ms,421ms;我的程序分别为265ms,281ms。读者可以复制第2,3章中代码自行验证。
比Floyd效率高了 (421-273)/421 ≈ 35.2%。
图3—1 Folyd和改进的星形Dijkstra效率对比
在该题的83位次AC结果中,时间排名第三,如图3—2所示,我不知道第一名的140ms怎么做到的……不会是SPFA吧?哪位大神讲解下。
图3—2 FOJ1544 AC结果排名前面部分(截止至:2013-10-26)
4 参考文献
[1] 王道论坛,2013年计算机专业基础综合考试指导全书,长沙:中南大学出版社,2012
[2] 作者不祥(网络资源),(书名)Matlab数学建模算法全收录,百度网盘下载