洛谷P3371,Dijkstra算法模板(优先队列优化)

无优先队列优化且用邻接矩阵存储图,这题如用邻接矩阵存储图会爆内存。

#include
#include
#include
#include
using namespace std;
const int inf = 0x3f3f3f3f;
const int p = 10005;
int a[p][p];//存放点与点的距离
int dist[p];//源点到各个点的最短距离
int pre[p];//计算过的点
int vis[p];//判断是否已经加入pre,是否已访问
int n, m;
int st; //源节点
void Dijkstra(int v)
{
    int i, j;
    for (i = 0; i < n; ++i)
    {
        if (i != v)
        {
            dist[i] = a[v][i];
        }
        vis[i] = false;
    }
    vis[v] = true;
    dist[v] = 0;
    pre[0] = v;
    //对各个数组进行初始化
    for (i = 0; i < n; ++i)
    {
        int minset = inf;
        int u = v;
        for (j = 0; j < n; ++j)
        {
            if (!vis[j] && dist[j] < minset)
                //找到剩余节点中最小的节点
            {
                u = j;
                minset = dist[u];
            }
        }
        vis[u] = true;  //u代表当前未加入数组且数值最小的点 
        //将节点标记为以访问,相当于加入s数组中
        for (j = 0; j < n; ++j)
        {
            if (!vis[j] && a[u][j] < inf)
                //a[u][j] < MAXN指更新u的可达点
            {
                if (dist[u] + a[u][j] < dist[j])
                {
                    dist[j] = dist[u] + a[u][j];
                    pre[j] = u;
                    //储存得出最短路径的前一个节点,用于路径还原
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d", &n, &m, &st);
    memset(a, 0x3f, sizeof(a));
    memset(dist, 0x3f, sizeof(dist));


    int i, j;
    for (i = 0; i < m; ++i)
    {
        int x, y, d;
        scanf("%d %d %d", &x, &y, &d);
        a[x - 1][y - 1] = min(a[x - 1][y - 1],d);
    }


    //int v;
    //scanf("%d",&v);
    Dijkstra(st-1);  //数组里是从0到n-1,所以传入st-1
	for (int i = 0; i < n; ++i)  //输出V0到各点的最小路径长度 
	{
		if(i)
			printf(" ");
		if(dist[i]!=inf)
			printf("%d", dist[i]);			
		else
			printf("2147483647");
	}

    //        int k=n-1;    //输出V0到vn-1的前驱,即路径 
    //        while(pre[k]!=k){
    //        	cout<
    //        	k=pre[k];
    //		} 

            /*for(int i = 0;i < n;++i)
            {
                printf("%d ",s[i]);
            }
            printf("\n");
            for(int i = 0;i < n;++i)
            {
                printf("%d ",pre[i]);
            }
            printf("\n");*/
    return 0;
}

以邻接表存储,优先队列优化:

#include
#include
#include
#include
#include
#include
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 10005;

int dist[maxn];//源点到各个点的最短距离

int pre[maxn];//计算过的点
int vis[maxn];//判断是否已经加入pre,是否已访问
int n, m;
int st; //源节点

struct Edge {
	int u; int d;
	Edge(int uu, int dd) {
		u = uu;
		d = dd;
	}
	bool operator<(const Edge& e) const //注意这个const必须要加上,不然编译错误
	{
		return d > e.d; //小顶堆,大顶堆将>改为<
	}

};
vector<Edge>g[maxn];


void Dijkstra(int v)
{
	priority_queue<Edge>q;
	memset(pre, -1, sizeof(pre));
	memset(dist, 0x3f, sizeof(dist));
	dist[v] = 0;
	q.push(Edge(v, 0));
	while (!q.empty()) {
		Edge e1 = q.top();
		q.pop();
		int u = e1.u;  //顶点编号
		if (vis[u])  //说明dist[u]已经是当前最短,这句话很关键!可以大幅度减少不必要的操作
			continue;
		vis[u]=1;
		for (int i = 0; i < g[u].size(); i++) {
			Edge e2 = g[u][i];
			if (dist[e2.u] > dist[u] + e2.d) {
				dist[e2.u] = dist[u] + e2.d;
				//pre[e2.u] = u;   //记录e2.u的前驱,用于保存路径
				q.push(Edge(e2.u, dist[e2.u]));
			}
		}
	}
	
}
int main()
{
	scanf("%d%d%d", &n, &m, &st);
	
	for (int i = 0; i < m; ++i)
	{
		int x, y, d;
		scanf("%d %d %d", &x, &y, &d);
		g[x - 1].push_back(Edge(y-1,d)); //规定序号从0到n-1
	}

	Dijkstra(st-1);  //图里是从0到n-1,所以传入st-1
	for (int i = 0; i < n; ++i)  //输出V0到各点的最小路径长度 
	{
		if(i)
			printf(" ");
		if(dist[i]!=inf)
			printf("%d", dist[i]);			
		else
			printf("2147483647");
	}

	//int k=n-1;    //输出V0到vn-1的前驱,即路径 
	//while(pre[k]!=-1){
	//    cout<
	//    k=pre[k];
	//} 
	return 0;
}

你可能感兴趣的:(洛谷题解,迪杰斯特拉算法)