给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径。
(来自题解)
首先考虑暴力维护,显然极端数据就会炸裂,那么用什么来维护呢?
由于log(n*m)=log(n)+log(m)
OK,这道题到此结束
我们只要把乘积转化为对数,最后再还原就可以了,因为精度要求,所以还是记录路径好些。
#include<cstdio> #include<cstdlib> #include<vector> #include<cstring> #include<queue> #include<cmath> using namespace std; int n,m; const int N=1003,inf=1<<30; struct node { int v;double w; node(int vv,double ww) { v=vv,w=ww; } node(){} }; vector <node > g[N]; int sz[N],path[N][2]; double dis[N]; struct nd { int v;double d; nd(int vv,double dd) { v=vv,d=dd; } nd(){} bool operator < (const nd & o) const { return d>o.d; } }; priority_queue <nd> q; void dijk() { for(int i=2;i<=n;i++) dis[i]=inf; q.push(nd(1,0)); while(!q.empty() ) { int t=q.top() .v;double dd=q.top() .d; q.pop() ; if(dd!=dis[t]) continue; if(t==n) break; for(int i=0;i<sz[t];i++) { int nx=g[t][i].v ; if(dis[nx] > dis[t]+log(g[t][i].w ) ) { dis[nx]=dis[t]+log(g[t][i].w ); path[nx][0]=t,path[nx][1]=g[t][i].w ; q.push(nd(nx,dis[nx])); } } } } int ans=1,mod=9987; void get_path() { int v=n; while(v!=1) { ans=(ans*path[v][1])%mod; v=path[v][0]; } } int main() { scanf("%d%d",&n,&m); int u,v,w; for(int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); g[u].push_back(node(v,w)); } for(int i=1;i<=n;i++) sz[i]=g[i].size() ; dijk(); get_path(); printf("%d ",ans); return 0; }