Description
当路由器收到一个终端或者其它路由器发过来的报文时,它必须选项择最快的一条通信线路通向报文所指向的目标机器(目标机器可能是一个终端,也可能是另一个路由器)。众所周知,在两个路由器之间可能有多条通信线路,你的任务就是给出两个路由器之间最短通信时间。
每一个路由器都有一个IP来标识它自己,这个标识是唯一的。任意两点之间的通信时间单位是毫秒,每条通信线路都是全双工的(双向的)。
Input
第一行为两个整数n和m,n表示有多少个路由器,m表示有多少条通信线路。(2<=n<=100,1<=m<=1000)
接下去的m行用来描述路由器之间的线路。每行包括三个元素,两个路由器的IP地址和它们之间通信所花费的时间。
然后一行是一个整数t,表示有多少个报文。(1<=t<=1000)
接下去的t行是报文。每个报文占一行,为了简化问题,我们在每行中给出两个IP地址,分别是目标地址和源地址。你要做的就是求出两者之间的最短时间。
Output
对于每个报文,输出一行。每行只包含一个整数,表示报文给的两个IP地址之间的最短通信时间。如果不存在这样的通路,或者IP地址并不存在,则输出-1。
Sample Input
4 5
168.120.1.1 168.120.1.2 15
168.120.1.1 168.120.1.4 47
168.120.1.1 168.120.1.3 10
168.120.1.2 168.120.1.4 15
168.120.1.3 168.120.1.4 25
3
168.120.1.1 168.120.1.4
168.120.1.3 168.120.1.4
168.120.1.3 202.12.12.12
Sample Output
30
25
-1
题目分析:每个路由器看作一个顶点,建立一张带权无向图,运用Folyd算法求出定点对之间的最短路径。
需要注意的是,每个IP地址需要通过一定的方式映射到正整数中作为每个路由器的"名称",以下代码采用的是map<string,int>的映射,当然还可尝试其它映射方式。
AC代码如下:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <string>
using namespace std;
#define MAXN 105//最大顶点个数
const int INF = 0x3f3f3f3f;
int dis[MAXN][MAXN], path[MAXN][MAXN];
map<string, int> mp;
int n, m;//n个顶点、m条边
int pos=1;//用于映射IP地址
void Folyd()
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
void init()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i != j)
dis[i][j] = INF;//初始化为无穷大
else
dis[i][j] = 0;//初始化为0
}
}
int index(const string &x)
{//对一个IP地址返回它的顶点编号
map<string, int>::iterator it;
int t;
it = mp.find(x);
if(it != mp.end())//该IP已有顶点编号
t = it->second;
else
{//为该IP建立一个顶点编号
t = pos;
mp.insert(pair<string, int>(x, pos++));
}
return t;
}
int main( )
{
cin>>n>>m;
string s, str;
int u, v, cost;
init();
while(m--)
{
cin>>s>>str>>cost;
u = index(s);
v = index(str);
dis[u][v] = cost;
dis[v][u] = cost;
//建立无向图
}
Folyd();
cin>>m;
while(m--)
{
cin>>s>>str;
map<string, int>::iterator it;
it = mp.find(s);
if(it != mp.end())
u = it->second;
else
u = 0;
it = mp.find(str);
if(it != mp.end())
v = it->second;
else
v = 0;
if(u && v && (dis[u][v] != INF))//u、v顶点均存在且u到v有通路
{
cout<<dis[u][v]<<endl;
}
else
cout<<"-1"<<endl;
}
return 0;
}
------------------------------------------------------------------------------------------------------------------------------------
思考:如果要打印出两个路由器最短通路上的经过的路由器怎么办?
-----------------------------------------------------------
如果要打印两个路由器最短通路上的经过的路由器,那么需要一个二维数组用来保存,定义path[i][j]表示i到j上j的前一个顶点,这样,我们只需在每次的松弛操作过程中保存path[i][j]中j的前一个顶点就行了。
void Folyd()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
path[i][j] = i;//初始化
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
path[i][j] = path[k][j];//保存路径上的顶点
}
}
}
路径是保存了,怎么打印出呢?
void print_path(int u, int v)
{//参数u、v是某两个IP地址对应的顶点编号(u--->v)
while(u != v)
{
for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
if(it->second == v)//在map中找到value为v的key输出
{
cout<<it->first<<"<---";
break;
}
v = path[u][v];//依次向前索引一个顶点
}
for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
if(it->second == u)//在map中找到value为u的key输出
cout<<it->first<<endl;
}
完整代码如下:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <string>
using namespace std;
#define MAXN 105//最大顶点个数
const int INF = 0x3f3f3f3f;
int dis[MAXN][MAXN], path[MAXN][MAXN];
map<string, int> mp;
int n, m;//n个顶点、m条边
int pos=1;//用于映射IP地址
void Folyd()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
path[i][j] = i;//初始化
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
path[i][j] = path[k][j];//保存路径上的顶点
}
}
}
void init()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i != j)
dis[i][j] = INF;//初始化为无穷大
else
dis[i][j] = 0;//初始化为0
}
}
void print_path(int u, int v)
{//参数u、v是某两个IP地址对应的顶点编号(u--->v)
while(u != v)
{
for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
if(it->second == v)//在map中找到value为v的key输出
{
cout<<it->first<<"<---";
break;
}
v = path[u][v];//依次向前索引一个顶点
}
for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
if(it->second == u)//在map中找到value为u的key输出
cout<<it->first<<endl;
}
int index(const string &x)
{//对一个IP地址返回它的顶点编号
map<string, int>::iterator it;
int t;
it = mp.find(x);
if(it != mp.end())//该IP已有顶点编号
t = it->second;
else
{//为该IP建立一个顶点编号
t = pos;
mp.insert(pair<string, int>(x, pos++));
}
return t;
}
int main( )
{
cin>>n>>m;
string s, str;
int u, v, cost;
init();
while(m--)
{
cin>>s>>str>>cost;
u = index(s);
v = index(str);
dis[u][v] = cost;
dis[v][u] = cost;
//建立无向图
}
Folyd();
cin>>m;
while(m--)
{
cin>>s>>str;
map<string, int>::iterator it;
it = mp.find(s);
if(it != mp.end())
u = it->second;
else
u = 0;
it = mp.find(str);
if(it != mp.end())
v = it->second;
else
v = 0;
if(u && v && (dis[u][v] != INF))
{
cout<<dis[u][v]<<endl;
print_path(u, v);//输出u到v的最短路径
}
else
cout<<"-1"<<endl;
}
return 0;
}