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;
}
Folyd算法參考:http://blog.csdn.net/niushuai666/article/details/6772706