逃生
【题目描述】
小 J 在一次旅行中感染了一只可以分裂细菌,这种细菌在出现一分钟后会分裂成两只
相同重量的细菌,其中一只不再分裂,另一只在一分钟后继续分裂。小 J 想尽快找到杀菌
草药,然而可供行走的路并不多。山里共有 n 个水池与 m 条路,每条路连接两个水池,
走过这条道路需要花费一定的时间。小 J 感染时在 s 号水池,杀菌草药生长在 t 号水池里。
小 J 每经过一个水池时都要喝一口水来补充体力,但是细菌也会产生变化:现存所有细菌
都会合体为一只,重量为所有细菌重量之和,合体一分钟后继续分裂。然而,小 J 并不知
道这一点,每经过一个水池,他依然会去喝水。你需要为小 J 画出一条从 s 号水池到 t 号
水池的路线,使得小 J 到达 t 号水池时身上的细菌重量最小。数据保证有且只有一组解。
【输入格式】
第一行四个整数 n m s t
接下来 m 行,每行三个整数 l r w,表示 l 号水池与 r 号水池间有一条道路,花费为 w 分
钟(喝水不花费时间)。同一对 l r 之间可能有多条道路
【输出格式】
第一行一个整数 k,表示路线长度
接下来一行 k 个整数,依次表示你画出的路线中经过的每个点
【样例输入】
4 4 1 4
1 2 0
1 3 2
3 4 1
2 4 4
【样例输出】
3
1 2 4
【数据范围】
30%的数据保证 n ≤ 50;w ≤ 10
100%的数据保证 2 ≤ n ≤ 10000;1 ≤ m ≤ 30000;0 ≤ w ≤ 1000;s ≠ t;l ≠ r
很显然一下就能转换成 d[v]=d[u]*(w[u, v]+1)的等式。
但是对于这种数据,显然是会爆long long的
于是用对数离散,因为log(nm)=logn+logm
于是就变成了普通的SPFA
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 struct Node 9 { 10 int next,to; 11 double dis; 12 }edge[600001]; 13 int head[100001],num,n,m,s,t; 14 int len[100001],pre[100001]; 15 double dist[100001]; 16 bool vis[100001]; 17 void add(int u,int v,double w) 18 { 19 num++; 20 edge[num].next=head[u]; 21 head[u]=num; 22 edge[num].to=v; 23 edge[num].dis=w; 24 } 25 void SPFA(int S) 26 {int i; 27 queue<int>Q; 28 for (i=0;i<=n;i++) 29 dist[i]=1000000000.0; 30 len[S]=1;dist[S]=0; 31 Q.push(S); 32 while (Q.empty()==0) 33 { 34 int u=Q.front(); 35 Q.pop(); 36 vis[u]=0; 37 for (i=head[u];i;i=edge[i].next) 38 { 39 int v=edge[i].to; 40 if (dist[v]>dist[u]+edge[i].dis) 41 { 42 dist[v]=dist[u]+edge[i].dis; 43 pre[v]=u; 44 len[v]=len[u]+1; 45 if (vis[v]==0) 46 { 47 Q.push(v); 48 vis[v]=1; 49 } 50 } 51 } 52 } 53 } 54 void print(int S,int x) 55 { 56 if (x!=S) 57 print(S,pre[x]); 58 printf("%d ",x); 59 } 60 int main() 61 {int u,v,i; 62 double d; 63 cin>>n>>m>>s>>t; 64 for (i=1;i<=m;i++) 65 { 66 scanf("%d%d%lf",&u,&v,&d); 67 add(u,v,log2(d+1)); 68 add(v,u,log2(d+1)); 69 } 70 SPFA(s); 71 cout<<len[t]<<endl; 72 print(s,t); 73 }