您的位置:首页 > 其它

1008.最短路径问题

2014-04-25 19:55 169 查看
题目描述:

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入:

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。

(1<n<=1000, 0<m<100000, s != t)

输出:

输出 一行有两个数, 最短距离及其花费。

样例输入:

3 2

1 2 5 6

2 3 4 5

1 3

0 0

样例输出:
9 11

典型的迪杰斯特拉(Dijkstra)算法。关于图的表示方法有两种,一种是采用邻接矩阵,一种采用邻接表。

采用邻接矩阵的最重要的就是三个数组:

1.c[][]:图的表示方法。

2.dist[]:表示当前点到源点的最短距离。

3.known[]:表示该点是否被访问过。

下面是一个标准的求最短路径的Dijkstra算法代码:

测试用例:

5 7

1 2 10

1 4 30

1 5 100

2 3 50

3 5 10

4 3 20

4 5 60

1 5

3 2

1 2 5 

2 3 4 

1 3

输出:60  9

#include <iostream>

using namespace std;

const int MaxInt = 999999;
const int MaxNum = 100000;

int c[MaxNum][MaxNum];  //邻接矩阵
int dist[MaxNum];       //每个节点到源点的最短距离
bool visited[MaxNum];   //每个节点是否访问过

void Dijkstra(int s, int n)
{
for(int i = 1; i <= n; ++i)
dist[i] = c[s][i];

dist[s] = 0;
visited[s] = true;

//依次访问接下来的n - 1个unknown节点
for(int i = 1; i <= n - 1; ++i)
{
int tmp = MaxInt; //当前最短距离
int v = s; // 当前的节点

//在所有unknown节点中找到和源点距离最短的节点
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && dist[j] < tmp)
{
v = j;
tmp = dist[j];
}
}

//找到了和源点距离最短的unknown节点,更改其访问数组
visited[v] = true;

//然后更新其邻接的边,所有的边都要访问一次,都可能会更新
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && c[v][j] < MaxInt)
{
int tmp_dist = dist[v] + c[v][j];
if(tmp_dist < dist[j])
dist[j] = tmp_dist;
}
}
}
}

int main()
{
int n,line;  // n代表节点数目,line代表路径数
while(cin >> n >> line)
{
//跳出条件
if(n == 0 && line == 0)
break;

//初始化邻接矩阵
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
c[i][j] = MaxInt;

for(int i = 0; i < line; ++i)
{
int p,q,len;
cin >> p >> q >> len;
if(len < c[p][q])//如果有重边
{
c[p][q] = len;
c[q][p] = len;  //无向图 如果有向图这句话就去掉
}
}

//初始化最短距离
for(int i = 1; i <= n; ++i)
dist[i] = MaxInt;

//初始化访问数组
for(int i = 1; i <= n; ++i)
visited[i] = false;

int s,t;  //s,t分别为需要求的两点
cin >> s >> t;
Dijkstra(s,n);
cout << dist[t] << endl;

}
return 0;
}


此题涉及到距离和花费,不像传统的最短路径算法只要求最短路径,所以可以设立一个结构体。用来记录每个节点的距离和花费。这题WA了很久,原因是数据很变态。把最大值开大一点就OK~

#include <iostream>

using namespace std;

const int MaxInt = 1000000000 ;
const int MaxNum = 1001;

struct Node
{
int len;
int cost;
};

Node c[MaxNum][MaxNum];  //图的表示数组
Node dist[MaxNum];       //每个节点到源点的最短距离以及花费
bool visited[MaxNum];   //每个节点是否访问过

void Dijkstra(int s, int n)
{
for(int i = 1; i <= n; ++i)
{
dist[i].len = c[s][i].len;
dist[i].cost = c[s][i].cost;
}

dist[s].len = 0;
dist[s].cost = 0;
visited[s] = true;

//依次访问接下来的n - 1个unknown节点
for(int i = 1; i <= n - 1; ++i)
{
int tmp = MaxInt; //当前最短距离
int v = s; // 当前的节点

//在所有unknown节点中找到和源点距离最短的节点
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && dist[j].len < tmp)
{
v = j;
tmp = dist[j].len;
}
}

//找到了和源点距离最短的unknown节点,更改其访问数组
visited[v] = true;

//然后更新其邻接的边,所有的边都要访问一次,都可能会更新
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && c[v][j].len < MaxInt)
{
int tmp_len = dist[v].len + c[v][j].len;
int tmp_cost = dist[v].cost + c[v][j].cost;
if(tmp_len < dist[j].len)
{
dist[j].len = tmp_len;
dist[j].cost = tmp_cost;
}
else if(tmp_len == dist[j].len && tmp_cost < dist[j].cost)
{
dist[j].cost = tmp_cost;
}
}
}
}
}

int main()
{
int n,line;  // n代表节点数目,line代表路径数
while(cin >> n >> line)
{
//跳出条件
if(n == 0 && line == 0)
break;

//初始化邻接矩阵
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
c[i][j].len = MaxInt;
c[i][j].cost = MaxInt;
}

for(int i = 0; i < line; ++i)
{
int p,q,len,cost;
cin >> p >> q >> len >> cost;
if(len < c[p][q].len || (len == c[p][q].len && cost < c[p][q].cost))//如果有重边
{
c[p][q].len = len;
c[q][p].len = len;
c[p][q].cost = cost;
c[q][p].cost = cost;
}
}

//初始化最短距离
for(int i = 1; i <= n; ++i)
{
dist[i].len = MaxInt;
dist[i].cost = MaxInt;
}

//初始化访问数组
for(int i = 1; i <= n; ++i)
visited[i] = false;

int s,t;  //s,t分别为需要求的两点
cin >> s >> t;
Dijkstra(s,n);
cout << dist[t].len << " " << dist[t].cost << endl;

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: