九度oj-最短路径问题
题目描述:
给你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
题目分析:
题目本身不难,编写时细心一点!
主要学习一下图的邻接链表表示。
有几点需要注意:由于图是无向的,所以在用链表存储的时候记得把b也push进去
# include<stdio.h>
# include<vector>
using namespace std;
# define N 10001
struct edge
{
int next;//下一个顶点
int length;//两个顶点之间的边长
int cost;//两个顶点之间的代价
};
int main()
{
int n,m;
vector<edge> ed[N];
bool mark[N];//判断当前点是否已经被遍历
int dis[N];//最短距离
int minCost[N];//最短距离对应的代价
int i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
//初始化
for(i=1;i<=n;i++)
{
ed[i].clear();
}
while(m--)
{
int a,b,len,cos;
scanf("%d%d%d%d",&a,&b,&len,&cos);
edge tmp;
tmp.next=b;
tmp.length=len;
tmp.cost=cos;
ed[a].push_back(tmp);
tmp.next=a;
ed[b].push_back(tmp);//记得把b也push进去
}
int S,T;
scanf("%d%d",&S,&T);
//初始化
for(i=1;i<=n;i++)
{
mark[i]=false;
dis[i]=-1;
minCost[i]=0;
}
mark[S]=true;
dis[S]=0;
int newP=S;
for(i=1;i<n;i++)//对剩余的n-1个顶点遍历
{
for(j=0;j<ed[newP].size();j++)//对s的邻接遍历
{
int t=ed[newP][j].next;
int le=ed[newP][j].length;
int co=ed[newP][j].cost;
// printf("%d\n",t);
if(mark[t]==true)
continue;
if(dis[t]==-1||dis[t]>dis[newP]+le||(dis[t]==dis[newP]+le&&minCost[t]>minCost[newP]+co))
{//这个地方容易漏掉一种情况,就是最短路径相同时需要对对应的时间做判断
dis[t]=dis[newP]+le;
minCost[t]=minCost[newP]+co;
}
}
//寻找下一个要遍历的点,全局搜索
int min=10000000;
for(k=1;k<=n;k++)
{
if(mark[k]==true)
continue;
if(dis[k]==-1)
continue;
if(dis[k]<min)
{
min=dis[k];
newP=k;
}
}
mark[newP]=true;
}
printf("%d %d\n",dis[T],minCost[T]);
}
return 0;
}