EOJ1028-路由器

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章