首页 > 试题广场 >

最短路径

[编程题]最短路径
  • 热度指数:745 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 128M,其他语言256M
  • 算法知识视频讲解

给定的有n个顶点和m条边的有向图中,求出s到t的最短距离。


输入描述:
输入第一行,四个整数n,m,s,t;
接下来m行,每行三个整数a,b,c,表示有条连接a到b的边,长度为c。
注意重边的情况。对于100%的数据,。边权


输出描述:
输出s到t的最短距离,要是s无法到t,则输出-1。
示例1

输入

3 3 1 3
1 3 3
1 2 1
2 3 1

输出

2
djs算法
import java.io.*;
import java.util.*;


public class Main {

  static int n;
  static int[] h;
  static int[] e;
  static int[] ne;
  static int idx = 0;
  static int[] w;
  static int m;
  static int[] dis;
  static boolean[] vs;


  public static void add(int x,int y,int val){
    e[idx] = y;
    ne[idx] = h[x];
    w[idx] = val;
    h[x] = idx++;
  }

  public static void main(String[] args) throws IOException {
    BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
    String[] line = buf.readLine().split(" ");
    n = Integer.parseInt(line[0]);
    m = Integer.parseInt(line[1]);
    int s = Integer.parseInt(line[2]);
    int t = Integer.parseInt(line[3]);
    h = new int[n + 10];
    e = new int[100010];
    ne = new int[100010];
    w = new int[100010];
    dis = new int[n + 10];
    vs = new boolean[n + 10];

    Arrays.fill(h,-1);

    for (int i = 0; i < m; i++){
      line = buf.readLine().split(" ");
      int x = Integer.parseInt(line[0]);
      int y = Integer.parseInt(line[1]);
      int val = Integer.parseInt(line[2]);
      add(x,y,val);
    }

    int res = dij(s,t);

    System.out.println(res);

  }

  public static int dij(int s,int t){
    Arrays.fill(dis,Integer.MAX_VALUE >> 1);
    dis[s] = 0;
    for (int i = 1; i <= n; i++){
      int node = -1;
      for (int j = 1; j <= n; j++){
        if (!vs[j] && (node == -1 || dis[j] < dis[node])){
          node = j;
        }
      }
      vs[node] = true;
      for (int j = h[node]; j != -1; j = ne[j]){
        int child = e[j];
        if (!vs[child]){
          dis[child] = Math.min(dis[child],dis[node] + w[j]);
        }
      }
    }
    if (dis[t] >= (Integer.MAX_VALUE >> 1)) return -1;
    return dis[t];
  }

}


发表于 2021-03-18 22:22:56 回复(0)
用的dijkstra单源最短路径算法,不知道为什么只能通过60%,也没有出错用例可以查看,看到评论区一个答案都没有,就把我自己的贴上来吧,望日后有大佬指点。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()){
            int n = in.nextInt();
            int m = in.nextInt();
            int start = in.nextInt();
            int end = in.nextInt();
            HashMap<Integer,Node> nodes = new HashMap<>();
            for (int i = 0; i < m; i++) {
                int from = in.nextInt();
                int to = in.nextInt();
                int weight = in.nextInt();
                if(!nodes.containsKey(from)){
                    nodes.put(from,new Node(from));
                }
                if(!nodes.containsKey(to)){
                    nodes.put(to,new Node(to));
                }
                Node fromNode = nodes.get(from);
                Node toNode = nodes.get(to);
                Edge newEdge = new Edge(weight,fromNode,toNode);
                fromNode.nexts.add(toNode);
                fromNode.edges.add(newEdge);
            }
            System.out.println(getShortestPath(nodes,start,end));
        }
        in.close();
    }

    public static int getShortestPath(HashMap<Integer,Node> nodes, int start, int end){
        HashMap<Node,Integer> distanceMap = new HashMap<>();
        distanceMap.put(nodes.get(start),0);
        HashSet<Node> selectedNodes = new HashSet<>();
        Node minNode = getMinDistanceAndUnselectedNode(distanceMap,selectedNodes);
        while (minNode!=null){
            int distance = distanceMap.get(minNode);
            for(Edge edge : minNode.edges){
                Node toNode = edge.to;
                if(!distanceMap.containsKey(toNode)){
                    distanceMap.put(toNode,distance+edge.weight);
                }else {
                    distanceMap.put(toNode,Math.min(distanceMap.get(toNode),distance+edge.weight));
                }
            }
            selectedNodes.add(minNode);
            minNode = getMinDistanceAndUnselectedNode(distanceMap,selectedNodes);
        }
        return distanceMap.get(nodes.get(end));
    }

    private static Node getMinDistanceAndUnselectedNode(HashMap<Node, Integer> distanceMap, HashSet<Node> touchedNodes){
        Node minNode = null;
        int minDistance = Integer.MAX_VALUE;
        for(Map.Entry<Node,Integer> entry : distanceMap.entrySet()){
            Node node = entry.getKey();
            int distance = entry.getValue();
            if(!touchedNodes.contains(node) && distance<minDistance){
                minNode = node;
                minDistance = distance;
            }
        }
        return minNode;
    }

    static class Node{
        int id;
        ArrayList<Node> nexts;
        ArrayList<Edge> edges;

        public Node(int id) {
            this.id = id;
            this.nexts = new ArrayList<>();
            this.edges = new ArrayList<>();
        }
    }

    static class Edge{
        int weight;
        Node from;
        Node to;

        public Edge(int weight, Node from, Node to) {
            this.weight = weight;
            this.from = from;
            this.to = to;
        }
    }
}


发表于 2020-04-05 15:07:08 回复(0)
```
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;

const int N = 100010;
typedef pair<int, int> PII;
int n, m, s, t, idx=1;
int dist[N], h[N], e[N], ne[N], w[N];
bool st[N];

void add(int a, int b, int c) {
    w[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dijstra() {
    memset(dist, 0x3f3f3f, sizeof dist);
    dist[s] = 0;

    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, s});
   
    while (heap.size()) {
        auto k = heap.top();
        heap.pop();

        int distance = k.first, ver = k.second;
        if (st[ver])continue;

        for (int i = h[ver]; i != -1; i = ne[i]) {
            int j = e[i];
            if (dist[j] > distance + w[i]) {
                dist[j] = distance + w[i];
                heap.push({ dist[j], j });
            }
        }
    }
}
int main() {
    scanf("%d%d%d%d", &n, &m, &s, &t);
    memset(h, -1, sizeof h);
    while (m--) {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        add(x, y, z);
    }
    dijstra();

    if (dist[t] > 0x3f3f3f / 2)
        printf("-1");
    else
        printf("%d", dist[t]);

    return 0;
}
// 64 位输出请用 printf("%lld")

```
发表于 2023-12-14 20:16:22 回复(0)
#include<stdio.h>
#include<vector>
using namespace std;
struct E{
    int next;
    int c;
};
vector<E> edge[10001];
int Dis[10001];
bool mark[10001];
int main(){
    int n,m,s,t;
    while(scanf("%d%d%d%d",&n,&m,&s,&t)!=EOF){
        for(int i=1;i<=n;i++)
            edge[i].clear();
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            E tmp;
            tmp.next=b;
            tmp.c=c;
            edge[a].push_back(tmp);
        }
        for(int i=1;i<=n;i++){
            Dis[i]=-1;
            mark[i]=false;
        }
        Dis[s]=0;
        mark[s]=true;
        int newp=s;
        for(int i=1;i<n;i++){
            for(int j=0;j<edge[newp].size();j++){
                if(mark[edge[newp][j].next]==true) continue;
                if(Dis[edge[newp][j].next]==-1||Dis[edge[newp][j].next]>Dis[newp]+edge[newp][j].c){
                    Dis[edge[newp][j].next]=Dis[newp]+edge[newp][j].c;
                }
            }
            int Max=123123123;
            for(int j=1;j<=n;j++){
                if(mark[j]==true) continue;
                if(Dis[j]==-1) continue;
                if(Dis[j]<Max){
                    Max=Dis[j];
                    newp=j;
                }
            }
            mark[newp]=true;
           
        }
        printf("%d\n",Dis[t]);
    }
    return 0;
}
发表于 2020-09-10 22:27:59 回复(0)
不想自定义类, 想把代码尽量写的简单一点, 但一直卡在70%没有通过, 报错为数组越界, 想不明白为什么会数组越界. 或许是因为没有处理重边?

算法就是dijkstra, 首先不创建新数组, 就地执行, 不会出现问题, 然后使用一个dist来记录访问过的结点.

import java.util.*;
public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();

        int[][] matrix = new int[n + 1][n + 1];

        int from = input.nextInt();
        int to = input.nextInt();


        for (int i = 0; i < m; i++) {
            int r = input.nextInt();
            int c = input.nextInt();
            if (matrix[r][c] != 0) matrix[r][c] = Math.min(matrix[r][c], input.nextInt());
            else matrix[r][c] = input.nextInt();
        }

        input.close();

        if(n==0||m==0||from>n||to>n){
            System.out.println(-1);
            return;
        }

        dijkstra(matrix,from,to);

        System.out.println(matrix[from][to]==0?-1:matrix[from][to]);
    }

    public static void dijkstra(int[][] matrix, int source,int target) {
        int[] dist = new int[matrix.length];
        dist[source]++;
        int min = Integer.MAX_VALUE;
        int transI = 0;
        int minI = 0;
        for (int l = 1; l < matrix.length; l++) {
            for (int i = 1; i < matrix.length; i++) {
                if (dist[i] == 0) {
                    if (matrix[source][transI] != 0 && matrix[transI][i] != 0) {
                        if (matrix[source][i] != 0) {
                            matrix[source][i] = Math.min(matrix[source][i], matrix[source][transI] + matrix[transI][i]);
                        } else matrix[source][i] = matrix[source][transI] + matrix[transI][i];
                    }
                    if ( matrix[source][i]!=0&&min > matrix[source][i]) {
                        minI = i;
                        min = matrix[source][i];
                    }
                }
            }
            transI = minI;
            dist[transI]++;
            min = Integer.MAX_VALUE;
            if(transI==target) return;
        }
    }
}
编辑于 2020-04-14 10:00:58 回复(0)
#include<iostream>
#include<stdio.h>
#include<vector>
#include<string.h>
#include<string>
#include<algorithm>
using namespace std;

struct edg{
	int v;
	int w;
	
};

const int max_n=10001;
const int INF=100000;

int n,m,s,t;
bool vis[max_n];
vector<int> tempath;
vector<string> res;
bool flag;

void Dfs(int d,vector<int> pre[max_n],vector<edg> G[max_n]){
	
	if(d==s){
		tempath.push_back(d);
		string str="";
		for(int i=tempath.size()-1;i>=0;i--){
			str+=tempath[i]+'0';
		}
		flag=1;
		res.push_back(str);
		tempath.pop_back();//无参数!! 
		return;
	}
	tempath.push_back(d);
	for(int i=0;i<pre[d].size();i++){
		Dfs(pre[d][i],pre,G);
	}
	tempath.pop_back();
	
}

int djs(int d[],vector<int> pre[max_n],vector<edg> G[max_n]){
	for(int i=1;i<=n;i++){
		int u=-1,min=INF;
		for(int j=1;j<=n;j++){
			if(vis[j]==false && min>d[j]){
				u=j;
				min=d[j];
			}
		}
		if(u==-1){
			return -1;
		}
		vis[u]=true;
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i].v;
			if(vis[v]==false && d[u]+G[u][i].w<d[v]){
				d[v]=d[u]+G[u][i].w;
				pre[v].clear();
				pre[v].push_back(u);
			}else if(vis[v]==false && d[u]+G[u][i].w==d[v] ){
				pre[v].push_back(u);
			}
			
		}
		
		
	}
	
}


int main(){
	freopen("D:\\in.txt","r",stdin);
	while(cin>>n>>m>>s>>t){
		vector<int> pre[max_n];
		vector<edg> G[max_n];
		flag=0;
	    vis[max_n]=false;
		int d[max_n];
		fill(d,d+max_n,INF);
		d[s]=0;
		for(int i=0;i<m;i++){
			int k,j,weight;
			edg e1,e2;
			cin>>k>>j>>weight;
			e1.v=j;
			e1.w=weight;
			G[k].push_back(e1);
		}
		djs(d,pre,G);
		Dfs(t,pre,G);
		sort(res.begin(),res.end());
		if(flag==0){
			cout<<"-1"<<endl;
		}else{
			cout<<d[t]<<endl;
		}
	tempath.clear();
	res.clear();
	} 
	return 0;
}




先用djs算出最短路径,同时存储前驱结点,最后用DFS深度遍历每一个最短路径
编辑于 2020-04-08 17:57:06 回复(0)

问题信息

上传者:小小
难度:
6条回答 3189浏览

热门推荐

通过挑战的用户

最短路径