タイトル:与えられたn点から、sからtへの最短経路を見つけます。そのうちの2つの方法(混合可能)があります。1つは、指定されたmの有向エッジ(ui、vi、wi)を取ることです。種は任意の点xから任意の点yまでであり、そのコストはc ∗(x xor y)です。
単純な構築方法はO(n ^ 2 + m)ですが、実際には、x-> yの重みを持つエッジを他のエッジで置き換えることができ、xをバイナリに1ビットずつ分割できます。最終的に変更はyに到達し、このときに渡される重みも明らかにwです。
たとえば、次のとおりです。
001(2)から010(2)に移動する場合、2 ^ 0 + 2 ^ 1を費やす必要があります。ただし、最短パスは優れた性質を持っているため、エッジを分解できます。 001(2)から000(2)まで、次に000(2)から010(2)まで、コストは同じです。
つまり、点xの場合、彼をx * 2 ^ kに接続するだけでよいので、O(nlogn + m)に最適化され、再度dijを実行します。
コード:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 名前空間std を使用 ; 8 int n、m、c、st、sd、x、y、val; 9 struct node { 10 int to、next、w; 11 } ed [ 5000005 ]; 12 int dis [ 5000005 ]、vis [ 5000005 ]、head [ 5000005 ]、cnt; 13インラインvoid add( int u、int v、int w){ 14 ed [++ cnt] .next = head [u]; 15 ed [cnt] .to = v; 16 ed [cnt] .w = w; 17 head [u] = cnt; 18 } 19インラインint read(){ 20 int x = 1、a = 0 ; 21 文字 ch = getchar(); 22 while(ch < ' 0 ' || ch> ' 9 ' ){ 23 if(ch ==' - ')x = -1 ; 24 ch = getchar(); 25 } 26 ながら、(CH <= ' 9 ' && CH> = ' 0 ' ){ 27 、A = A * 10 + CH - ' 0 ' 。 28 ch = getchar(); 29 } 30は x * aを返します。 31 } 32 priority_queue <pair < int、int >> q; 33インラインvoid Dij(int s){ 34 q.push(make_pair(0、s)); memset(vis、0、sizeof(vis)); memset(dis、63、sizeof(dis)); dis [s] = 0 ; 35 while(!q.empty()){ 36 int x = q.top()。second; 37 q.pop(); 38 であれば(VIS [X])続けます。 39 vis [x] = 1 ; 40 のために(登録int型 ; I iが= Iがヘッド= [X] {ED [I] .next)を 41 int to = ed [i] .to; 42 if(dis [to]> dis [x] + ed [i] .w){ 43 dis [to] = dis [x] + ed [i] .w; 44 q.push(make_pair(-dis [to]、to)); 45 } 46 } 47 } 48 リターン; 49 } 50 int main(){ 51 n = read(); m = read(); c = read(); 52 for(int i = 1 ; i <= m; i ++ ){ 53 x = read()、y = read()、val =読んだ(); 54 add(x、y、val); 55 } 56 int lgn = floor(log2(n))+ 1 ; 57 n =(1 << lgn)-1 ; 58 (for register int i = 1 ; i <= n; i ++ ) 59 for(register int j = 0 ; j <lgn; j ++ ) 60 add(i、i ^(1 << j)、(1 << j )* c); 61 st = read()、sd = read(); 62 Dij(st); 63 cout << dis [sd]; 64 }