题意:
小明现在要追讨一笔债务,已知有n座城市,每个城市都有编号,城市与城市之间存在道路相连(每条道路都是双向的),经过任意一条道路需要支付费用。小明一开始位于编号为1的城市,欠债人位于编号为n的城市。小明每次从一个城市到达另一个城市需要耗时1天,而欠债人每天都会挥霍一定的钱,等到第k天后(即第k+1天)他就会离开城n并再也找不到了。小明必须要在他离开前抓到他(最开始为第0天),同时希望自己的行程花费和欠债人挥霍的钱的总和最小,你能帮他计算一下最小总和吗?
题解:
dij的一个变式题,只需要,虽然这只是一个变式题,但我还真没想出来,看了题解才会的。。。
只需要把visited和dis这两个数组多开出一维空间来维护一下第几天走到的哪个点即可。
最后遍历一边 1到k天,所有dis[n]的值,取最小的即可。
代码:
/*Keep on going Never give up*/ #pragma GCC optimize(3,"Ofast","inline") #include <bits/stdc++.h> #define endl '\n' #define ios std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0); //#define int long long const int maxn = 2e4+10; const int MaxN = 0x3f3f3f3f; const int MinN = 0xc0c0c00c; typedef long long ll; const int mod = 1e9+7; using namespace std; bool visited[1010][1010]; struct wazxy{ int to,w,next; }edge[maxn]; int head[maxn],dis[1010][1010],cnt=1; int n,m,k; int p[maxn]; inline void add(int u,int v,int w){ edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } struct node{ int day,id,dis; node(int a,int b,int c){id=a,dis=b,day=c;} bool operator < (const node & a)const {return dis>a.dis;} }; void dij(){ dis[0][1]=0; priority_queue<node> q; q.push(node(1,0,0)); while(!q.empty()){ node temp=q.top(); q.pop(); if(visited[temp.day][temp.id]) continue; visited[temp.day][temp.id]= true; for(int i=head[temp.id];i;i=edge[i].next){ int v=edge[i].to; int w=edge[i].w; if(temp.day+1<=k&&dis[temp.day+1][v]>dis[temp.day][temp.id]+w+p[temp.day+1]){ dis[temp.day+1][v]=dis[temp.day][temp.id]+w+p[temp.day+1]; q.push(node(v,dis[temp.day+1][v],temp.day+1)); } } } } int main(){ ios cin>>n>>m>>k; for(int i=0;i<m;i++){ int u,v,w; cin>>u>>v>>w; add(u,v,w); add(v,u,w); } for(int i=1;i<=k;i++){ cin>>p[i]; } memset(visited,false,sizeof visited); memset(dis,MaxN,sizeof dis); dij(); int ans=MaxN; for(int i=1;i<=k;i++){ ans=min(ans,dis[i][n]); } if(ans==MaxN) cout<<-1; else cout<<ans<<endl; return 0; }