最短路径问题

题目描述:
给你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


#include<stdio.h>
#define max 1001
struct E
{
  int next;//下一个点 
  int d;//长度 
  int p;//花费      
};
int n,m;
struct E edge[max][max];//存边
int dis[max];//存到每一个顶点的最短距离
int cost[max];//存最短距离对应的花费
int mark[max];//标志有没有加入集合 
void init()//初始化 
{
  int i;
  for(i=1;i<max;i++)
  {
     dis[i]=-1;//表示不可达
     mark[i]=0;//表示还未加入集合
     cost[i]=0;// 初始花费为0                  
  }
} 
//=======================================
//栈的相关操作
int size[max];
void init_stack()//初始化栈 
{
      int i;
      for(i=1;i<max;i++)
      size[i]=0;
}
 
void push(int a,int b,int d,int p)//入栈操作 
{
  //因为是无向图,所以是双向的,赋值两遍
  edge[a][size[a]].next=b;
  edge[a][size[a]].d=d;
  edge[a][size[a]].p=p;
  size[a]++;
  edge[b][size[b]].next=a;
  edge[b][size[b]].d=d;
  edge[b][size[b]].p=p;
  size[b]++; 
}
//==============================================
int main()
{
  while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
  {
   init();//初始化 
   init_stack();//初始化栈 
   int i,j;
   for(i=0;i<m;i++)
   {
     int a,b,d,p;
     scanf("%d%d%d%d",&a,&b,&d,&p);                
     push(a,b,d,p);
   }
   int s,t;//起点和终点
   scanf("%d%d",&s,&t);
   int newP=s;//初始找的点为起点
   mark[s]=1;
   dis[s]=0;//自己到自己为0 
   cost[s]=0;//花费也为0 
   for(i=1;i<n;i++)//开始遍历n-1次,每一次都找出一个点加入集合 
   {
      for(j=0;j<size[newP];j++)
      {
         int t=edge[newP][j].next;
         int d=edge[newP][j].d;
         int p=edge[newP][j].p;
          
         //当满足三种情况时,进行替换
         //分别是,1原本是不可达的,2原本的可达但是这个更小,3原本的和现在的相等,但是现在的花费更加便宜 
         if(dis[t]==-1||dis[newP]+d<dis[t]||(dis[newP]+d==dis[t]&&cost[newP]+p<cost[t]))
         {
            dis[t]=dis[newP]+d;
            cost[t]=cost[newP]+p;                                                                                 
         }                         
      }
       
      mark[newP]=1;//标记加入了集合
        
      int min=123123123;
      //找寻下一个newP
      for(j=1;j<=n;j++)
      {
         if(mark[j]==1) continue;//已经是集合的元素的也直接跳过 
         if(dis[j]==-1) continue;//不可达就跳过 
         if(min>dis[j])
         {
          min=dis[j];
          newP=j;          
         }                 
      } 
   }
    
   printf("%d %d\n",dis[t],cost[t]);                                              
  }
}

import java.util.*;
public class Main {
 
    public static void main(String[] args) {
        Scanner cin=new Scanner(System.in);
        while(cin.hasNext())
        {
            int n=cin.nextInt();
            int m=cin.nextInt();
            if(n==0&&m==0)
                break;
            int[][] edge=new int[n][n];
            int[][] val=new int[n][n];
            for(int i=0;i<m;i++)
            {
                int x=cin.nextInt()-1;
                int y=cin.nextInt()-1;
                int a=cin.nextInt();
                int b=cin.nextInt();
                if(edge[x][y]==0||edge[x][y]>a||(edge[x][y]==a&&val[x][y]>b))
                {
                    edge[x][y]=a;
                    edge[y][x]=a;
                    val[x][y]=b;
                    val[y][x]=b;
                }
            }
            int s=cin.nextInt()-1;
            int t=cin.nextInt()-1;
            int[] road=new int[n];
            int[] value=new int[n];
            int now=s;
            int tt=0;
            road[now]=-1;
            for(int i=0;i<n-1;i++)
            {
                int min=-1;
                for(int j=0;j<n;j++)
                {
                    if(edge[now][j]==0)continue;
                    if(road[j]==0||road[j]>tt+edge[now][j]||(road[j]==tt+edge[now][j]&&value[j]>value[now]+val[now][j]))
                    {
                        road[j]=tt+edge[now][j];
                        value[j]=value[now]+val[now][j];
                    }
                    if(road[j]>0&&(min==-1||road[min]>road[j]||(road[min]==road[j]&&value[min]>value[j])))
                        min=j;
                }
                now=min;
                tt=road[now];
                road[now]=-1;
                if(now==t)
                    break;
            }
            System.out.println(tt+" "+value[t]);
        }
    }
 
}
 



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值