题目大意:
有n个点的连通图,有m次可以将某一条边权值减半的机会。
不同的机会可以叠加作用于同一条边。
求1~n的最短路。
思路:
拆点,记录1到每个点在使用不同次数的机会后的最短路,然后直接跑Dijkstra即可。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<functional> 5 #include<ext/pb_ds/priority_queue.hpp> 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const double inf=1e9; 14 const int V=51,M=11; 15 struct Edge { 16 int to; 17 double w; 18 }; 19 std::vector<Edge> e[V]; 20 inline void add_edge(const int &u,const int &v,const double &w) { 21 e[u].push_back((Edge){v,w}); 22 } 23 struct Vertex { 24 double dis; 25 int id,k; 26 bool operator > (const Vertex &another) const { 27 return dis>another.dis; 28 } 29 }; 30 int n,m,s,t; 31 double d[V][M]; 32 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 33 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[V][M]; 34 inline void dijkstra() { 35 for(register int i=1;i<=n;i++) { 36 for(register int j=0;j<=m;j++) { 37 p[i][j]=q.push((Vertex){d[i][j]=(i==s&&j==0)?0:inf,i,j}); 38 } 39 } 40 while(q.top().dis!=inf) { 41 const Vertex x=q.top(); 42 for(register unsigned i=0;i<e[x.id].size();i++) { 43 const Edge &y=e[x.id][i]; 44 for(register int i=0;i<=m-x.k;i++) { 45 if(x.dis+y.w/(1<<i)<d[y.to][x.k+i]) { 46 q.modify(p[y.to][x.k+i],(Vertex){d[y.to][x.k+i]=x.dis+y.w/(1<<i),y.to,x.k+i}); 47 } 48 } 49 } 50 q.modify(p[x.id][x.k],(Vertex){inf,0,0}); 51 } 52 } 53 int main() { 54 n=getint(),m=getint(); 55 s=1,t=n; 56 for(register int i=1;i<=n;i++) { 57 for(register int j=1;j<=n;j++) { 58 const int w=getint(); 59 if(w) add_edge(i,j,w); 60 } 61 } 62 dijkstra(); 63 printf("%.2f ",d[t][m]); 64 return 0; 65 }