题目1008:最短路径问题
时间限制:1 秒
内存限制:32 兆
特殊判题:否
提交:11139
解决:3795
-
题目描述:
-
给你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
-
答疑:
解题遇到问题?分享解题心得?讨论本题请访问:http://t.jobdu.com/thread-7732-1-1.html
分析:自己用的是Dijkstra算法写的,感觉特别好;大致思想也就是找权值最小的边,如果有边相等,则找花费最小的边。
#include <iostream>
#include <fstream>
using namespace std;
struct cost
{
int d;//距离
int p;// 花费
}dist[1001];
struct graph
{
int n,e; //节点数和边数
}g;
int mapd[1001][10001];//存的是边的距离
int mapp[1001][10001]; //存的是边的花费
const int INF = 2100000000; //这里视为权值无穷大
int path[1001];//记录选取的中间节点
void Dijkstra(graph g,int s0);
int main()
{
ifstream in;
in.open("1.txt");
int n,m;
int s0,s1;
while(in>>n>>m,n||m)//当且仅当n和m全为false时表达式的值为false,否则为true,
{ //也就是如果n和m中只要有一个不为0表达式的值就为1,while就一直循环
g.n=n;
g.e=m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
mapd[i][j]=INF;
mapp[i][j]=INF;
}
for(int i=1;i<=m;i++)
{
int j,k;
in>>j>>k;
in>>mapd[j][k]>>mapp[j][k];//无向图,二个方向都要设置权值
mapd[k][j]=mapd[j][k];
mapp[k][j]=mapp[j][k];
}
in>>s0>>s1;
Dijkstra(g,s0);
cout<<dist[s1].d<<" "<<dist[s1].p<<endl;
}
return 0;
}
void Dijkstra(graph g,int s0)
{
int set[1001];//节点访问的标志
int min1,min2,i,j,u;
for(i=1;i<=g.n;i++)
{
dist[i].d=mapd[s0][i];
dist[i].p=mapp[s0][i];
set[i]=0;
if(mapd[s0][i]<INF)
path[i]=s0;
else
path[i]=-1;
}
set[s0]=1;
path[s0]=-1;
for(int i=1;i<=g.n;i++)
{
min1=INF;//距离的最小值
min2=INF;//花费的最小值
for(j=1;j<=g.n;j++)
{
if(set[j]==0 && dist[j].d<min1)//选择距离小的边
{
u=j;
min1=dist[j].d;
min2=dist[j].p;
}else if(set[j]==0 && dist[j].d==min1 && dist[j].p<min2)//若边的距离相等,选择花费小的边
{
u=j;
min1=dist[j].d;
min2=dist[j].p;
}
}
set[u]=1;//将其加入到最短路径的点集里
for(j=1;j<=g.n;j++)
{
if(set[j]==0 && dist[u].d+mapd[u][j]<dist[j].d)
{
dist[j].d=dist[u].d+mapd[u][j];
dist[j].p=dist[u].p+mapp[u][j];
path[j]=u;
}
else if(set[j]==0 && dist[u].d+mapd[u][j]==dist[j].d && dist[u].p+mapp[u][j]<dist[j].p)
{
dist[j].d=dist[u].d+mapd[u][j];
dist[j].p=dist[u].p+mapp[u][j];
path[j]=u;
}
}
}
}
自己又用Floyd写了,但由于这个算法的复杂度为o(n^3),所以提交时间通不过
#include <iostream>
#include <fstream>
using namespace std;
int a[1001][1001];
int b[1001][1001];
const int INF=210000;
void Floyd(int n);
int main()
{
ifstream in;
in.open("1.txt");
int n,m;
int s,t;
while(in>>n>>m,m||n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
b[i][j]=a[i][j]=INF;
for(int i=1;i<=m;i++)
{
int j,k;
in>>j>>k;
in>>a[j][k]>>b[j][k];
a[k][j]=a[j][k];
b[k][j]=b[j][k];
}
in>>s>>t;
Floyd(n);
cout<<a[s][t]<<" "<<b[s][t]<<endl;
}
return 0;
}
void Floyd(int n)
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(a[i][j]>a[i][k]+a[k][j])
{
a[i][j]=a[i][k]+a[k][j];
b[i][j]=b[i][k]+b[k][j];
}else if(a[i][j]==a[i][k]+a[k][j] && b[i][j]>b[i][k]+b[k][j])
{
b[i][j]=b[i][k]+b[k][j];
}
}
}
找了一下别人写的
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
int n, m;
int map[1010][1010];
bool vi[1010];
int cost[1010][1010];
int dis[1010];
int price[1010];
int s, t;
const int INF = 2100000000;
void init()
{
for (int i = 1; i <= n; ++ i)
{
vi[i] = false;
dis[i] = INF;
price[i] = INF;
for (int j = 1; j <= n; ++ j)
{
map[i][j] = INF;
}
}
for (int i = 0; i < m; ++ i)
{
int from, to, d, p;
scanf("%d%d%d%d", &from, &to, &d, &p);
map[to][from] = map[from][to] = d;
cost[to][from] = cost[from][to] = p;
}
scanf("%d%d", &s, &t);
}
void dijkstra()
{
dis[s] = 0;
price[s] = 0;
for (int k = 0; k < n; ++ k)
{
int index = -1;
int minn = INF;
for (int i = 1; i <= n; ++ i)
{
if (vi[i]==false && dis[i]<minn)
{
index = i;
minn = dis[i];
}
}
vi[index] = true;
for (int j = 1; j <= n; ++ j)
{
if (dis[j] > dis[index] + map[index][j])
{
dis[j] = dis[index] + map[index][j];
price[j] = price[index] + cost[index][j];
} else if (dis[j] == dis[index] + map[index][j])
{
price[j] = min(price[j], price[index]+cost[index][j]);
}
}
}
}
int main()
{
while (cin >> n >> m, n || m)
{
init();
dijkstra();
cout << dis[t] << " " << price[t] << endl;
}
return 0;
}