#C231107C. 最短路(path)


#C231107C. 最短路(path)

标签(Label)

  • 分层图
  • 最短路算法

网址(Website)

题目详情 - 最短路(path) - Super

题解 - 最短路(path) - Super

题目(Problem)

给定一个 $n$ 个点 $m$ 条边的无向图 $G$,求 $G$ 上 $1$ 到其他点的“最短路”的长度。

对于“最短路”的定义,假设一条路径上的边权依次为 $w_{1}, w_{2}, \ldots w_{k}$,定义 $S(w)=\min(w_{i})-\max(w_{i})+\sum w_{i}$ 为路径长度,求出在这个定义下的最短路。

范围: 对 $100 %$ 的数据:$n, m \leq 2 \times 10^{5}$;$1 \leq u, v \leq n$;$0<w \leq 10^{9}$。数据保证不存在自环。

题解(Solution)

$\qquad$为什么这个题解的形容这么,令人误解。

$\qquad$该题文字有误,题解代码却是对的。

$\qquad$由于题解代码太丑了,所以我用了 cx 大佬的代码,cx太强了,膜膜膜

修改后的题解(Repaired Solution)

$\qquad$代价的形式中对最大值和最小值的要求比较难处理, 无法记录到最短路中直接计算,但可以将最大最小边均改成任意, 即等价于对于每条路径可以选一条边免费, 选一条边计算两次, 问最短路。这样我们最优解一定是在某条路径上最大边免费, 最小边计算两次, 否则更劣。

$\qquad$那么这样就可以求分层图最短路了, 改为求 $(1,0)$ 到 $(i, 2)$ 的最短路, 对每条边 $(u,v, w)$, 连 $(u, k)$ 到 $(v, k)$ 权值为 $w$ ,$(u,0)$ 到 $(v, 1)$ 权值为 $2w$,$(u,1)$ 到 $(v,2)$ 权值为 $0$ 即可。

代码(Code)

我的代码(五层图)

$\qquad$第一层是原图;

$\qquad$第二、三层是先取 $min$ 后取 $max$ ;

$\qquad$第四、五层是先去 $max$ 后取 $min$ 。

#include<bits/stdc++.h>
#include<vector>
#include<queue>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define int long long
#define P pair<int,int>
inline int input(){int x1;return cin>>x1,x1;}
const int N = 1012345;
vector<P> ft[N];
int n,m;

priority_queue<P> q;
int d[N];
void dijkstra(int root){
	q.push({0,root}),d[root]=0;
	while(q.size()){
		int x=q.top().second;q.pop();
		for(auto p:ft[x]){
			int y=p.first,w=p.second;
			if(d[x]+w<d[y]){
				d[y]=d[x]+w;
				q.push({-d[y],y});
			}
		}
	}
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	string str("path");
	freopen((str+".in").c_str(),"r",stdin);
	freopen((str+".out").c_str(),"w",stdout);
	cin>>n>>m;For(i,1,m){
		int x1=input(),y1=input(),v=input();//第一层 
		int x2=x1+n,y2=y1+n;//第二层 
		int x3=x2+n,y3=y2+n;//第三层 
		int x4=x3+n,y4=y3+n;//第四层 
		int x5=x4+n,y5=y4+n;//第五层 
		
		//层内建点 
		ft[x1].push_back({y1,v});
		ft[y1].push_back({x1,v});
		ft[x2].push_back({y2,v});
		ft[y2].push_back({x2,v});
		ft[x3].push_back({y3,v});
		ft[y3].push_back({x3,v});
		ft[x4].push_back({y4,v});
		ft[y4].push_back({x4,v});
		ft[x5].push_back({y5,v});
		ft[y5].push_back({x5,v});
		//跨层建点 
		ft[x1].push_back({y2,v*2});
		ft[y1].push_back({x2,v*2});
		ft[x2].push_back({y3,0});
		ft[y2].push_back({x3,0});
		ft[x1].push_back({y4,0});
		ft[y1].push_back({x4,0});
		ft[x4].push_back({y5,v*2});
		ft[y4].push_back({x5,v*2});
	}
	memset(d,0x3f,sizeof(d));
	dijkstra(1);
	For(x,2,n) cout<<min({d[x],d[x+2*n],d[x+4*n]})<<' ';cout<<'\n';
	return 0;
}

cx的代码(四层图)

$\qquad$cx大佬 的博客网址: Huasushis ‘s Blog

$\qquad$其实就是: $min$ 代表跳 $1$ 层, $max$ 代表跳 $2$ 层。

#include <bits/stdc++.h>
#define int long long
#define N 200010
using namespace std;
int n, m;
int u, v, c;
int first[N * 3], nxt[N * 5], to[N * 5], w[N * 5], et;
void add(int u, int v, int c) {
  nxt[++et] = first[u];
  first[u] = et;
  to[et] = v;
  w[et] = c;
}
int dis[N][4];
#define pii pair<int, int>
#define piii pair<int, pii>
#define fi first
#define se second
#define mp make_pair
#define inf 0x3f3f3f3f
bool vis[N][4];
void dij() {
  memset(dis, 0x3f, sizeof(dis));
  priority_queue<piii, vector<piii>, greater<piii>> q;
  dis[1][0] = 0;
  q.emplace(0, mp(1, 0));
  while (!q.empty()) {
    int u = q.top().se.fi;
    int s = q.top().se.se;
    q.pop();
    if (vis[u][s]) continue;
    vis[u][s] = 1;
    for (int i = first[u]; i; i = nxt[i]) {
      if (!(s & 1)) {//0-->1  2-->3 (走min)
        if (dis[to[i]][s | 1] > dis[u][s] + w[i] * 2) {
          dis[to[i]][s | 1] = dis[u][s] + w[i] * 2;
          q.emplace(dis[to[i]][s | 1], mp(to[i], s | 1));
        }
      }
      if (!(s & 2)) {//0-->2   1-->3  (走max)
        if (dis[to[i]][s | 2] > dis[u][s]) {
          dis[to[i]][s | 2] = dis[u][s];
          q.emplace(dis[to[i]][s | 2], mp(to[i], s | 2));
        }
      }
      if (!s) {//0-->3 (走普通边到3)
        if (dis[to[i]][3] > dis[u][s] + w[i]) {
          dis[to[i]][3] = dis[u][s] + w[i];
        } 
      }
      if (dis[to[i]][s] > dis[u][s] + w[i]) {//0-->0  1-->1  2-->2  3-->3(在当前层走普通边)
        dis[to[i]][s] = dis[u][s] + w[i];
        q.emplace(dis[to[i]][s], mp(to[i], s));
      }
    }
  }
}
signed main() {
  freopen("path.in", "r", stdin);
  freopen("path.out", "w", stdout);
  scanf("%lld%lld", &n, &m);
  for (int i = 1; i <= m; ++i) {
    scanf("%lld%lld%lld", &u, &v, &c);
    add(u, v, c);
    add(v, u, c);
  }
  dij();
  for (int i = 2; i <= n; ++i) printf("%lld ", dis[i][3]);
  return 0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录