<题目链接>
题目大意:
Rinne 学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图。当我们在这个图上经过一条边的时候,这个图上所有边的边权都会发生变动。定义变动函数 f(x)=1/(1−x),表示我们在图上走过一条边后,图的边权变动情况。这里指的“图的变动”的意思是将每条边的边权代入上函数,得到的值即为该次变动后的边权。现在 Rinne 想要知道,在这个变动的图上从 1 到 n 的最短路径。因为 Rinne 不喜欢负数,所以她只需要你输出经过的边权权值绝对值之和最小的那个值就可以了。输出答案保留三位小数。
解题分析:
所谓动态图,其实就是你走到这个点所对应的步数不同,图的边权所对应的值也随之发生改变。我们仔细观察这个函数,手动推导几项之后发现,该函数是一个周期变化的函数,并且周期为3。很明显本题就被转化成为了一个分层图最短路的模型,分成三层,分别对应到达该点步数%3的情况。并且,因为本题的边权都取绝对值,所以最好用Dijkstra(或者BFS,据说出题人卡SPFA,雾……)。
#include <bits/stdc++.h> using namespace std; const int N = 1e5+5, M = 3e5+5; #define clr(a,b) memset(a,b,sizeof(a)) #define rep(i,s,t) for(int i=s;i<=t;i++) double dis[N][3]; int n,m,cnt; int head[N],vis[N][3]; const double INF = 1e15; struct Node{ int loc,lev;double dist; Node(int _loc=0,int _lev=0,double _dist=0.0):loc(_loc),lev(_lev),dist(_dist){} bool operator < (const Node &tmp)const { return tmp.dist<dist; } }node[N][3]; struct Edge{ int to,nxt;double w; }edge[M<<1]; inline void init(){ cnt=0;clr(head,-1); } inline void addedge(int u,int v,double w){ edge[++cnt].to=v,edge[cnt].nxt=head[u]; edge[cnt].w=w,head[u]=cnt; } inline double cal(double x,int tp){ //该函数是一个以3为周期的周期函数,并且记得取绝对值 if(tp==0)return x*1.0; if(tp==1)return fabs(1/(1.0-x)); return fabs(1-1.0/x); } inline void Dij(){ rep(i,1,n) rep(j,0,2){ node[i][j].loc=i,node[i][j].lev=j; node[i][j].dist=INF;vis[i][j]=0; } priority_queue<Node>q; node[1][2].dist=0; q.push(node[1][2]); //因为题目是说经过一条边后,图上边的权值才发生改变,所以这里从node[1][2]开始,即起始点走了一条边之后,图的边权边权才发生改变 while(!q.empty()){ Node now=q.top();q.pop(); int tmp1=now.loc,tmp2=now.lev; if(vis[tmp1][tmp2])continue; vis[tmp1][tmp2]=1; for(int i=head[tmp1];~i;i=edge[i].nxt){ int v=edge[i].to;double cost=edge[i].w; if(node[v][(tmp2+1)%3].dist>node[tmp1][tmp2].dist+cal(cost,(tmp2+1)%3)){ node[v][(tmp2+1)%3].dist=node[tmp1][tmp2].dist+cal(cost,(tmp2+1)%3); q.push(Node(v,(tmp2+1)%3,node[v][(tmp2+1)%3].dist)); } } } } int main(){ init();scanf("%d%d",&n,&m); rep(i,1,m){ int u,v;double w;scanf("%d%d%lf",&u,&v,&w); addedge(u,v,w);addedge(v,u,w); } Dij(); double ans=INF; rep(i,0,2) ans=min(ans,node[n][i].dist); //printf("%.3lf ",node[n][i].dist); if(ans==INF)puts("-1"); else printf("%.3lf ",ans); }