Gym 101498L The Shortest Path(两种写法 spfa和暴力)

题目链接:https://vjudge.net/problem/Gym-101498L

在大佬那学了一手:
https://blog.csdn.net/qq_35781950/article/details/78561131#commentBox

题目:
ou are given a directed weighted graph with N nodes and M edges. Your task is to find the minimum shortest path between any pair of nodes in the graph. As the weight of the edges can be negative, the path is allowed to visit the same node multiple times.

Formally, let F(u, v) be the shortest path between the two nodes u and v, find the minimum F(u, v) over all pairs (u, v) (1 ≤ u, v ≤ N) (u ≠ v). If there is no path between a pair of nodes u and v, then F(u, v) = ∞.

Input
The first line of input contains a single integer T (1 ≤ T ≤ 100), the number of test cases.

The first line of each test case contains two integers N and M (2 ≤ N ≤ 2000) (1 ≤ M ≤ 5000), where N is the number of nodes in the graph, and M is the number of edges.

Each of the following M lines contains three integers U, V and C (1 ≤ U, V ≤ N) (U ≠ V) ( - 106 ≤ C ≤ 106), representing that there is an edge from node U to node V with cost C.

Note that the graph may contain multiple edges between the same pair of nodes in the same direction.

Output
For each test case, print the minimum length of a shortest path in the graph, or “-inf” if the length of the shortest path is negative infinity.

Example
Input
3
3 3
1 2 -1
2 3 -3
3 1 -5
4 5
1 3 0
1 2 -2
2 3 3
3 4 1
4 1 -1
4 4
1 2 5
2 3 -3
3 4 -3
1 4 2
Output
-inf
-3
-6

题意: 给你一个图,很多边,然后这些边有正有负,当形成环的时候,环里的点可以重复遍历,一直跑。题目是让你求最小的两点之间距离,如果有负环输出-inf即可。

思路: 用spfa先判断是否存在负环,建立一个超级源点0,0到任何点的距离都为0,以0为起点跑一遍最短路即可,但是开始用bfs实现spfa会超时,改为dfs就不会了。

spfa(dfs)代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>

using namespace std;

const int maxn =2000+5;
const int inf =0x3f3f3f3f;
int inq[maxn],head[maxn],T,N,M,pos,ans;//inq数组表示是否在dfs中
int d[maxn];//距离
bool flag;


struct Edge
{
    int to,val,next;
} edge[maxn*5];

void init()
{
    pos=0;
    ans=inf;
    memset(head,-1,sizeof(head));
    memset(inq,0,sizeof(inq));
    memset(d,inf,sizeof(d));
}

void add_edge(int from,int to,int val)//邻接链表
{
    edge[pos].to = to;
    edge[pos].val = val;
    edge[pos].next = head[from];
    head[from] = pos;
    pos++;
}

void spfa(int s)
{
    if(flag)
        return;
    inq[s]=1;
    for(int i=head[s]; i!=-1; i=edge[i].next)
    {
        Edge& e = edge[i];
        if(d[e.to]>d[s]+e.val)
        {
            d[e.to]=d[s]+e.val;
            if(!flag&&inq[e.to])//形成了负环
            {
                flag=true;
                break;
            }
            else
                spfa(e.to);
        }

    }
    inq[s]=0;//回溯
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        init();
        flag=false;
        scanf("%d%d",&N,&M);
        int a,b,c;
        for(int i=0; i<M; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            ans=min(ans,c);
        }
        if(ans>=0)//假如所有的边输入都为正的话,不这么判断,dfs找到的最小边永远是0。
        {
            printf("%d\n",ans);
            continue;
        }
        for(int i=1; i<=N; i++)//设置一个超级源点0
            add_edge(0,i,0);
        d[0]=0;

        spfa(0);

        if(flag)
        {
            printf("-inf\n");
            continue;
        }
        else
        {
            for(int i=1; i<=N; i++)
            {
                ans=min(ans,d[i]);
            }
            printf("%d\n",ans);
            continue;
        }
    }
    return 0;
}

暴力代码:

#include<bits/stdc++.h>
using namespace std;
const int inf=2000000009;
int kraw[5001][3];
int odl[2001];
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n,m;
        scanf("%d%d", &n, &m);
        int wyn=1000000009;
        for(int i=1; i<=n; i++)
            odl[i]=0;
        for(int i=1; i<=m; i++)
        {
            int a,b,c;
            scanf("%d%d%d", &a, &b, &c);
            kraw[i][0]=a;
            kraw[i][1]=b;
            kraw[i][2]=c;
            wyn=min(wyn,c);
        }
        int czy=1;
        int ile=0;
        while(czy==1 && wyn>-inf && ile<=n)
        {
            ile++;
            czy=0;
            for(int i=1; i<=m; i++)
                if(odl[kraw[i][1]]>odl[kraw[i][0]]+kraw[i][2])
                {
                    odl[kraw[i][1]]=odl[kraw[i][0]]+kraw[i][2];
                    wyn=min(wyn, odl[kraw[i][1]]);
                    czy=1;
                }
        }
        //cout<<wyn<<" "<<ile<<endl;
        if(ile>n || wyn<=-inf)
            printf("-inf\n");
        else
            printf("%d\n", wyn);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36300700/article/details/80139614