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;
}