• 【模板】 最短路


    单源最短路

    (Dijkstra)

    堆优化,用距离最小的点更新其他节点。

    • 不能处理有负权边的图。
      (O(mlogn))
    void dijkstra(int s) {
    	priority_queue <pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
    	dis[s] = 0;
    	q.push(make_pair(0,s));
    	while(!q.empty()) {
    		int u = q.top().second;
    		q.pop();
    		if(vis[u])continue;
    		vis[u] = true;
    		for(int i = head[u]; i; i = next[i]) {
    			int v = to[i];
    			if(dis[v] <= dis[u] + val[i]) continue;
    			dis[v] = dis[u] + val[i];
    			q.push(make_pair(dis[v],v));
    		}
    	}
    }
    

    (SPFA)

    (Bellman-ford)的队列优化。
    每次把能更新且不在队列里的点压入队列。

    • 可以用来判负环(一个点被压入队列超过(n)次);
    • 可以用来求差分约束
      将式子(x_i-x_j le k)变形为(x_ile x_j + k),连边(x_j ightarrow x_i),权值为(k),求单源最短路

    不稳定,最坏情况(O(mn))

    void spfa(int s) {
    	queue <int> q;
    	dis[s] = 0;
    	q.push(s);
    	vis[s] = true;
    	while(!q.empty()) {
    		int u = q.front();
    		q.pop();
    		vis[u] = false;
    		for(int i = head[u]; i; i = nxt[i]) {
    			int v = to[i];
    			if(vis[v])continue;
    			if(dis[v] <= dis[u] + val[i])continue;
    			dis[v] = dis[u] + val[i];
    			q.push(v);
    			vis[v] = true;
    		}
    	}
    }
    

    多源最短路

    (Floyd)

    先枚举中转点。
    有时候可以用于每次加入一个点的情况。
    (O(n^3))

    void Floyd() {
    	for(int k = 1; k <= n; k++)
    		for(int i = 1; i <= n; i++)
    			for(int j = 1; j <= n; j++)
    				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    }
    

    k短路

    (A*)

    先建反向边求出(t)到每个点的最短路,即为估计值。
    (bfs),优先队列的节点按当前距离+估计值排序。每个点都记录路径。
    每次走到(t)计数(+1)
    小数据范围骗分用

    struct node {
    	int id,now,sum;
    	vector <int> path;
    	bool operator < (const node & N) const {
    		return sum > N.sum;
    	}
    };
    
    void bfs(int s,int t) {
    	node u = (node) {
    		s,0,dis[s]
    	};
    	u.path.push_back(s);
    	priority_queue <node> q;
    	q.push(u);
    	while(!q.empty()) {
    		u = q.top();
    		q.pop();
    		if(u.id == t && ++tot == k) {
    			for(int i = 0; i < u.path.size(); i++)
    				printf("%d ",u.path[i]);
    			return;
    		}
    		for(int i = head[u.id]; i; i = nxt[i]) {
    			bool visit = false;
    			for(int j = 0; j < u.path.size(); j++)
    				if(to[i] == u.path[j]) {
    					visit = true;
    					break;
    				}
    			if(visit) continue;
    			node v = (node) {
    				to[i],u.now+w[i],u.now+w[i]+dis[to[i]],u.path
    			};
    			v.path.push_back(to[i]);
    			q.push(v);
    		}
    	}
    	printf("No");
    }
    

    最短路分层图

    (k)次免费或打折机会,(k)很小
    拆点(x,x+n...x+k*n)
    用掉一次机会即(x+i*n ightarrow y+(i+1)*n)
    这样建边后正常跑最短路即可。

    for(int i = 1; i <= k; i++) {
    	add(x+i*n,y+i*n,w);
    	add(x+(i-1)*n,y+i*n,0);
    }
    
  • 相关阅读:
    BZOJ3875 AHOI2014/JSOI2014骑士游戏(动态规划)
    Contest 9
    Contest 8
    Codeforces Round#514 Div.2 翻车记
    Contest 7
    安徽师大附中%你赛day6 T3 Hamsters [POI2010]CHO-Hamsters 解题报告
    2018.8 安徽师大附中培训游记
    安徽师大附中%你赛day5 T3 树上行走 解题报告
    安徽师大附中%你赛day4T2 演讲解题报告
    安徽师大附中%你赛day4T1 金字塔 解题报告
  • 原文地址:https://www.cnblogs.com/mogeko/p/13284223.html
Copyright © 2020-2023  润新知