Johnson's Algorithm

Johnson's Algorithm是一种解决图中所有顶点对之间的最短路径问题的算法,尤其适用于存在负权边的情况。该算法首先通过转化将含有负权边的图转化为不含负权边的图,然后使用Dijkstra算法求解。本文详细介绍了Johnson's Algorithm的步骤、转化过程及其实现,并通过实例分析其应用效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef DIJKSTRA_H
#define DIJKSTRA_H

#include <math.h>
#include <vector>
#include <climits>

using namespace std;

typedef struct
{
	int head;
	int tail;
	int cost;
} Edge;


void Dijkstra(vector<Edge> &E, vector<vector<int>> &Vtail, int nV, int nE, int s, int *spath);

#endif


#include "dijkstra.h"

int heap[10000];
int prior[10000];
int heapSize = 0;
//int pos2Id[1000];
int id2Pos[10000];
bool boolX[10000];

void InsertHeap(int id)
{
	heap[heapSize++] = id;
	id2Pos[id] = heapSize-1;
	int pos = heapSize-1;
	while (pos > 0)
	{
		int parent = pos-1 >> 1;
		if(prior[id] > prior[heap[parent]])
		{
			break;
		}
		int temp = heap[parent];
		heap[parent] = id;
		heap[pos] = temp;

		id2Pos[id] = parent;
		id2Pos[temp] = pos;

		pos = parent;
	}
}

void DeleteHeap(int id)
{
	int pos = id2Pos[id];
	if (pos < 0)
	{
		return;
	}

	heap[pos] = heap[--heapSize];
	id2Pos[heap[pos]] = pos;
	while (pos < (heapSize>>1))
	{
		int child = 2*pos+1;
		if (child+1< heapSize && prior[heap[child+1]] < prior[heap[child]])
		{
			child++;
		}

		if (prior[heap[pos]] <= prior[heap[child]])
		{
			break;
		}

		int temp = heap[pos];
		heap[pos] = heap[child];
		heap[child] = temp;

		id2Pos[temp] = child;
		id2Pos[heap[pos]] = pos;

		pos = child;
	}
}

int PopMin()
{
	int id = heap[0];
	heap[0] = heap[--heapSize];
	int pos = 0;
	id2Pos[heap[pos]] = pos;
	while (pos < (heapSize>>1))
	{
		int child = 2*pos+1;
		if (child+1< heapSize && prior[heap[child+1]] < prior[heap[child]])
		{
			child++;
		}

		if (prior[heap[pos]] <= prior[heap[child]])
		{
			break;
		}

		int temp = heap[pos];
		heap[pos] = heap[child];
		heap[child] = temp;

		id2Pos[temp] = child;
		id2Pos[heap[pos]] = pos;

		pos = child;
	}

	return id;
}


void Dijkstra(vector<Edge> &E, vector<vector<int>> &Vtail, int nV, int nE, int s, int *spath)
{
	// --------- Initial -------
	for (int i=0; i<nV; i++)
	{
		id2Pos[i] = -1;
		prior[i] = INT_MAX;
		boolX[i] = false;
	}
	// -------------------------
	prior[s] = 0;
	InsertHeap(s);

	while(heapSize >0)
	{
		int u = PopMin();
		boolX[u] = true;
		for (int i=0; i<Vtail[u].size(); i++)
		{
			int v = E[Vtail[u][i]].head;
			int w = E[Vtail[u][i]].cost;
			if (boolX[v])
			{
				continue;
			}

			DeleteHeap(v);
			prior[v] = min(prior[v], prior[u]+w);
			InsertHeap(v);
		}
	}

	for (int i=0; i<nV; i++)
	{
		spath[i] = prior[i];
	}
}



#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <climits>
#include "dijkstra.h"

using namespace std;

bool BellmanFordInit(vector<Edge> &E, int nV, int nE, int *pv)
{
    // ---------- Initial -------------
    int ** A = new int*[2];
    for (int i=0; i<2; i++)
        A[i] = new int[nV];

    for (int j=0; j<nV; j++)
    {
        A[0][j] = 0;
        A[1][j] = INT_MAX; 
    }
    // -----------------------------------
    int h;
    int t;
    int c;
    for (int i=1; i<nV+1; i++)
    {
        if(1 == i%2) 
        {
            for(int j=0; j<nE; j++)
            {
                h = E[j].head;
                t = E[j].tail;
                c = E[j].cost;

                A[1][h] = min(A[1][h], min(A[0][h], A[0][t]+c));
            }
        }
        else
        {
            for(int j=0; j<nE; j++)
            {
                h = E[j].head;
                t = E[j].tail;
                c = E[j].cost;

                A[0][h] = min(A[0][h], min(A[1][h], A[1][t]+c));
            }
       
        }
    }

    // --------- Judge ----------
    int sum =0;
    for(int j=0; j<nV; j++)
    {
        pv[j] = A[0][j];
        sum += A[1][j] - A[0][j];
    }

    delete []A;
    if(0 == sum)
        return true;
    else
        return false;
}


int RwSDijkstra(vector<Edge> &E, vector<vector<int>> &Vtail, int *pv, int nV, int nE, int s, int *spath)
{
	Dijkstra(E, Vtail, nV, nE, s, spath);
	int sp = INT_MAX;
	for (int i=1; i<nV; i++)
	{
		if (s != i)
		{
			sp = min(sp, spath[i]-pv[s]+pv[i]);
		}
	}


	return sp;
}


int main()
{
   ifstream infile;
   infile.open("g2.txt");

   // -------------------------
   string line;
   stringstream ss;
   getline(infile, line);
   ss << line;

   int nV, nE;
   ss >> nV;
   ss >> nE;

   // --------- Initialize ---------
   vector<vector<int>> Vtail(nV);
   vector<Edge> E(nE);
   // ------------
   ss.clear();
   line.clear();
   int n=0;
   while(getline(infile, line) && n<nE)
   {
        ss << line;

        int h;
        int t;
        int c;
        ss >> t;
        ss >> h;
        ss >> c;

        E[n].tail = t-1;
        E[n].head = h-1;
        E[n].cost = c;

        Vtail[t-1].push_back(n);

		ss.clear();
		line.clear();
		n++;
   }
   infile.close();

   // ------- Bellman-Ford ------ 
   int *pv = new int[nV];
   if (!BellmanFordInit(E, nV, nE, pv))
   {
        delete []pv;
        cout << "There is neg cycle" << endl;
        return -1;
   }

   // ------- Small cost -----
   int sss = INT_MAX;
   for (int i=1; i<nE; i++)
   {
	   sss = min(sss, E[i].cost);
   }
   cout << "Small edge : " << sss << endl;
    // ---------- Dijkstra -----------
   // Reweight 
   for (int i=0; i<nE; i++)
   {
	   int t = E[i].tail;
	   int h = E[i].head;
	   int c = E[i].cost;

	   E[i].cost = c + pv[t]-pv[h];
   }

   // All pair ---
   int *spath = new int[nV];
   int sp = INT_MAX;
   for (int i=0; i<nV; i++)
   {
	   sp = min(sp, RwSDijkstra(E, Vtail, pv, nV, nE, i, spath));
   }

   cout << "All pair short path : " << sp << endl;
   // -----------------
   delete[] spath;
   delete []pv;

   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值