최단 경로 템플릿-플로이드 알고리즘

Floyd 알고리즘

동적 프로그래밍의 아이디어에 기반한 실현 :
f[i, j, k]시작점 i와 끝점 j를 제외하고 i에서 j까지의 경로에서 1과 k 사이의 점만 통과 하는 모든 경로 의 최단 거리 를 나타냅니다 .

하나의 지점을 통과 할 수도 있고 여러 지점을 통과 할 수도 있고 그중 하나를 통과하지 못할 수도 있습니다.

동적 전달 방정식이 있습니다.f[i, j, k] = min(f[i, j, k - 1), f[i, k, k - 1] + f[k, j, k - 1]

인접 행렬 f를 사용하여 저장된 초기화 에지 정보는 f[i,j,0]i-> j가 정점없이 직접적인 상태 로 저장됩니다 .

F [난, J는, (1)]를 계산하고, 이는 I-의 경로> j는, 두 가지 선택이있다 정점 1. 통과 선택 여부 필요가 없다고 판정 된 경우에는, 경우에
F [I, J, 2 추구 ], i-> j의 경로는 정점 1과 2를 통과 할 필요가 없다고 판단됩니다. 이때 f [i, j, 1]은 정점 1을 통과 할 필요가없는 최단 경로를 찾았습니다. , 그리고이를 기반으로 정점 2 만 통과하면됩니다.

k 번째 레이어의 f [i, j]를 계산할 때 k-1 번째 레이어의 모든 상태를 먼저 계산해야합니다. 즉 , 인접 행렬2 차원 배열 f는 다음 여부를 판단 할 때마다 업데이트됩니다. 정점이 전달되지 않고 총 n 번 업데이트됩니다.
그리고 k = j 또는 k = i가 아니면 f[i,j]사용할 때마다 f[i,k]합계 f[k,j]되지만 f [i, i] = 0 이므로 이번에는 이 업데이트 가 사용되지 않을 것임을 증명할 수 있습니다. 추가하지 않기 때문에 업데이트 전후에 데이터를 유지하기 위해 배열을 열 필요가 없습니다.

1. 문제가 있습니다.Floy의 알고리즘이 처리해야하는 것: 자체 루프
Floyd 알고리즘은 음의 루프가있는 그래프를 처리 할 수 ​​없으며 (자체 루프의 가중치가 음수 일 때도 음의 루프입니다), 자체 루프의 가중치가 양수이면 작동하지 않습니다 . 인접 행렬의 주 대각선 (자기 자신까지의 거리)은 0입니다.

k = 1의 첫 번째 업데이트를 고려합니다. f [1,3] f[1,3]=f[1,1]+f[1,3]이 업데이트되면 이러한 업데이트가 발생하므로 자기 자신과의 거리를 0으로 지정해야합니다.
이것은 인접 행렬 저장의 정의이기도합니다. 데이터를 입력 할 때 자기 루프의 에지를 입력 할 때 (음의 가중치 루프가 없기 때문에 자기 루프의 마이너스 가중치를 가진 에지는 입력되지 않고 양수 만 입력됩니다), 따라서 최소값을 취할 수 있습니다. 이 상황을 처리 할 가장자리. (무거운 모서리 처리)
naive dijkstra 알고리즘의 저장에 인접 행렬을 사용하는 경우 효과가 없기 때문에 양의 가중치를 가진 자체 루프를 처리 할 필요가 없으므로 그 이유를 신중하게 분석하십시오.

둘째, 무거운 모서리 처리

인접 행렬 저장 그래프이기 때문에 하나의 에지 만 저장할 수 있으므로 가중치가 가장 작은 에지 만 저장됩니다. (음의 가중치 모서리가 있음)
주 대각선은 0이어야합니다.

문제에주의하십시오. 제목에는 음의 가중치 루프가 없어야하므로 자체 루프의 모서리도 양수 여야하므로 일반 모서리와 동일한 방식으로 처리 할 수 ​​있습니다.
먼저 주 대각선을 0으로 초기화합니다. , 그런 다음 최소값을 가져옵니다 (매번 0이어야 함).

3. 접근성 판단

f[i,j]=min(f[i,j],f[i,k]+f[k,j]), 업데이트 할 수있는 조건은 i에서 k까지 도달 할 수 있고 k에서 j도 도달 할 수 있다는 것 입니다. 모서리 중 하나에 도달 할 수없는 한 INF이며 업데이트 할 필요가 없습니다. f [i , j] = f [i, j]
판정 조건 :if (f[i][k]!=INF && f[k][j]!=INF)

이런 식으로 INF에 대한 부정적인 측면의 영향에 대해 걱정할 필요가 없습니다. 도달 할 수 없지만 거리는 INF가 아니라 INF보다 약간 작습니다.

제목 설명

n 개의 점과 m 개의 모서리가있는 유 방향 그래프가 주어지면무거운면자체 루프, 가장자리 가중치가 음수 일 수 있습니다.

k 개의 쿼리가 주어지면 각 쿼리에는 두 개의 정수 x 및 y가 포함되며, 이는 쿼리에 대한 지점 x에서 지점 y까지의 최단 거리를 나타냅니다. 경로가 존재하지 않으면 "불가능"을 출력합니다.

데이터 보증 그래프에는 음의 가중치 루프가 없습니다.

입력 형식 첫
번째 줄에는 세 개의 정수 n, m, k가 포함됩니다.

다음 m 개 행에서 각 행에는 세 개의 정수 x, y, z가 포함되어 있으며, 이는 점 x에서 점 y로 향하는 가장자리가 있고 변의 길이가 z임을 나타냅니다.

다음 k 개 행에서 각 행에는 쿼리 지점 x와 지점 y 사이의 최단 거리를 나타내는 두 개의 정수 x와 y가 포함됩니다.

출력 형식
총 k 개의 라인이 있으며, 각 라인은 질의 결과를 나타내는 정수를 출력하며 질의의 두 지점 사이에 경로가 없으면 "불가능"이 출력됩니다.

데이터 범위는
1≤n≤200,
1≤k≤n 2
1≤m≤20000이며
그림에 포함 된 측면 길이 절대 값은 10000을 초과하지 않습니다.

입력 샘플 :

3 3 2
1 2 1 // m 모서리 입력
2 3 2
1 3 1
2 1 // 다음은 k 쿼리입니다.
1 3

샘플 출력 :

불가능
1

암호

#include <iostream>
#include <cstring>

using namespace std;
const int N=210,INF=0x3f3f3f3f;
int dp[N][N];
int n,m,num;

void floyd()
{
    
    
    for (int k=1;k<=n;k++)  更新n次dp二维表,求出i->j在最多经过n个顶点的下的最短路径
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if (dp[i][k]!=INF && dp[k][j]!=INF) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}

int main()
{
    
    
    scanf("%d%d%d",&n,&m,&num);
    
    memset(dp,0x3f,sizeof dp);
    for (int i=0;i<=n;i++) dp[i][i]=0; //结点编号从1到n,0行0列用不到
    int a,b,c;
    while(m--) {
    
    
        scanf("%d%d%d",&a,&b,&c);
        dp[a][b]=min(dp[a][b],c); //处理重边,自环时c必大于0,所以主对角线还是0
    }
    floyd(); 
    //然后dp数组存储任意两个点之间的最短距离
    while(num--) {
    
    
        scanf("%d%d",&a,&b);
        int t=dp[a][b];
        if (t==INF) puts("impossible");
        else printf("%d\n",t);
    }
    
    return 0;
}

추천

출처blog.csdn.net/HangHug_L/article/details/114013732