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