题目1008:最短路径问题

题目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
来源:
2010年浙江大学计算机及软件工程研究生机试真题
答疑:

解题遇到问题?分享解题心得?讨论本题请访问: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;  
}  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值