1028 追债之旅 分层图或dp写法思路 最短路
链接:https://ac.nowcoder.com/acm/problem/14700
来源:牛客网
题目描述
小明现在要追讨一笔债务,已知有n座城市,每个城市都有编号,城市与城市之间存在道路相连(每条道路都是双向的),经过任意一条道路需要支付费用。小明一开始位于编号为1的城市,欠债人位于编号为n的城市。小明每次从一个城市到达另一个城市需要耗时1天,而欠债人每天都会挥霍一定的钱,等到第k天后(即第k+1天)他就会离开城n并再也找不到了。小明必须要在他离开前抓到他(最开始为第0天),同时希望自己的行程花费和欠债人挥霍的钱的总和最小,你能帮他计算一下最小总和吗?
输入描述:
第1行输入三个整数n,m,k,代表城市数量,道路数量和指定天数
第2-m+1行,每行输入三个整数u,v,w,代表起点城市,终点城市和支付费用。(数据保证无重边,自环)
第m+2行输入k个整数,第i个整数ai代表第i天欠债人会挥霍的钱。
数据保证:0<n≤1000,0<m≤10000,0<k≤10,1≤u,v≤n,0<w,ai≤1000
输出描述:
输出一行,一个整数,代表小明的行程花费和欠债人挥霍的钱的最小总和,如果小明不能抓住欠债人(即不能在第k天及之前到达城n),则输出-1。
示例1
分析
经过几天到达 n 的最短路。
每条边,都有第0天到第1 天,.....,第 k - 1 天 到第 k 天的边。分层建图
for(int i = 0;i<=k-1;i++)add(u + i * n,v + (i+1) * n,w);
最后计算的时候 从第一天开始枚举到第 k 天找最短路
for(int k = 1;k<=n;k++) ans = min(ans,sum[i] + dist[i * n + n]);
只要跑一边最短路,然后枚举每一天到达 n 的最短路 就可以了。
//-------------------------代码---------------------------- #define int ll const int N = 2e5+10; int n,m,k; int e[N],ne[N],w[N],h[N],idx; int a[N]; void add(int a,int b,int c) {e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++ ;} int dist[N]; bool vis[N]; void dij() { ms(dist,0x3f); ms(vis,0); priority_queue<pii,V<pii>,greater<pii>> q; q.push({0,1}); dist[1] = 0; while(q.size()) { auto tmp = q.top();q.pop(); int t = tmp.second; if(vis[t]) continue; vis[t] = 1; for(int i = h[t];~i;i=ne[i]) { int j = e[i],W = w[i]; if(dist[j] > dist[t] + W) { dist[j] = dist[t] + W; q.push({dist[j],j}); } } } } void solve() { cin>>n>>m>>k; ms(h,-1); fo(i,1,m) { int u,v,w;cin>>u>>v>>w; fo(j,0,k-1) { add(j * n + u,(j + 1) * n + v,w); } fo(j,0,k-1) { add(j * n + v,(j + 1) * n + u,w); } } fo(i,1,k) { cin>>a[i]; a[i] += a[i-1]; } dij(); int ans = inf; fo(i,1,k) { ans = min(ans,a[i] + dist[i * n + n]); } if(ans == inf) cout<<-1<<endl; else cout<<ans<<endl; } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------
dp写法参照之前的一道题,就是 dp[i][k] 表示枚举到 i 节点,用了 k 天的最短路
一样的