洛谷P9751 [CSP-J 2023] 旅游巴士
传送门:P9751 [CSP-J 2023] 旅游巴士
为了那个梦我们扬帆起航,为了理所到来的那天跨越无尽黑夜
由于这几天做的题目太少,我用小号立下flag:
导致果然做了一晚上。。。。
并且最后还是没做出来被我妈强制去睡觉了
题目意思:
题目很明白了,这里说几个要注意的点:
- 道路均只能单向通行
- 到达和离开景区的时间都必须是
的非负整数倍:说明在景区里呆着的时间也要是 的非负整数倍,即路径长度是 的非负整数倍 - 对于每条道路均设置了一个开放时间
,游客只有不早于 时刻才能通过这条道路:说明 起始时间+到达这个点的路径长度要
思路:一档档地想
1st:不存在合法方案
输出 “-1”,拿到 5 pts
2nd:考虑 ,
直接求从起点到终点的最短路径长度。
SPFA,启动!
#include<bits/stdc++.h> using namespace std; #define int long long int m,n,k;//先考虑 k = 1,a[i] = 0 的情况 const int maxn=10100; const int maxm=20100; int en; int fir[maxn]; struct edge{ int v,next; }ed[maxm]; void add_edge(int u,int v) { en++; ed[en].v=v; ed[en].next=fir[u]; fir[u]=en; } queue<int>q; int dist[maxn]; bool inque[maxn]; void SPFA(int r) { for(int i=1;i<=n;i++) { dist[i]=LLONG_MAX; } dist[r]=0; q.push(r); inque[r]=true; while(!q.empty()) { int now=q.front(); q.pop(); for(int i=fir[now];i;i=ed[i].next) { int p=ed[i].v; if(dist[now]+1<dist[p]) { dist[p]=dist[now]+1; if(!inque[p]){ q.push(p); inque[p]=true; } } } } } signed main() { cin>>n>>m>>k; for(int i=1;i<=m;i++) { int u,v,t; cin>>u>>v>>t; add_edge(u,v); } if(k==1){ SPFA(1); if(dist[n]==LLONG_MAX) cout<<-1<<endl; else cout<<dist[n]<<endl; } else cout<<-1<<endl; return 0; }
分值:15pts
3rd:只考虑 的情况。
如果在搜索最短路的时候,出现到了一条路的开放时间大于当前最短路,即从
因为每走一条路,需要的时间是
代码:
#include<bits/stdc++.h> using namespace std; #define int long long int m,n,k;//先考虑 k = 1,a[i] = 0 的情况 const int maxn=10100; const int maxm=20100; int en; int fir[maxn]; struct edge{ int v,next; int d; }ed[maxm]; void add_edge(int u,int v,int t) { en++; ed[en].v=v; ed[en].d=t; ed[en].next=fir[u]; fir[u]=en; } queue<int>q; int dist[maxn]; bool inque[maxn]; void SPFA(int r) { for(int i=1;i<=n;i++) { dist[i]=LLONG_MAX; } dist[r]=0; q.push(r); inque[r]=true; while(!q.empty()) { int now=q.front(); inque[now]=false; q.pop(); for(int i=fir[now];i;i=ed[i].next) { int p=ed[i].v; int t=ed[i].d; if(t>dist[now]) { if(t+1<dist[p])//1+t { dist[p]=t+1; if(!inque[p]){ q.push(p); inque[p]=true; } } } else if(dist[now]+1<dist[p]){ dist[p]=dist[now]+1; if(!inque[p]){ q.push(p); inque[p]=true; } } } } } signed main() { cin>>n>>m>>k; for(int i=1;i<=m;i++) { int u,v,t; cin>>u>>v>>t; add_edge(u,v,t); } if(k<=1){ SPFA(1); if(dist[n]==LLONG_MAX) cout<<-1<<endl; else cout<<dist[n]<<endl; } else cout<<-1<<endl; return 0; }
分值:30pts
Finally:考虑把 加进去
虽然好像考试拿到上面的分就能差不多
但是还是要做出这道题来啊!!!
首先,这部分我一开始是不会的,参考了洛谷上很多大佬的题解
上面我们已经说过:
如果在搜索最短路的时候,出现到了一条路的开放时间大于当前最短路,即从
时刻出发,到达这个点早了。我们就晚 的倍数出发。
即:如果现在的时间是
具体等待的时间
我们可以建立状态:定义
那么答案显然是
考虑转移:
- 如果
了,那么可以直接通过,则 。 - 否则令
,即我们在入口处等待一些时间,使得可以走到这条边,转移为 。
这是一个图上的 DP,我们可以使用 SPFA 的方法更新。即枚举每条遍历到的边
代码:
#include<bits/stdc++.h> using namespace std; #define int long long const int maxn=10100; const int maxm=20100; const int maxk=105; int n,m,k; int en; int fir[maxn]; struct edge{ int v,a; int next; }ed[maxm]; inline int read() { int f=1,x=0;char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-48; ch=getchar(); } return x*f; } void add_edge(int u,int v,int a) { en++; ed[en].a=a,ed[en].v=v; ed[en].next=fir[u]; fir[u]=en; } int dist[maxn][maxk]; queue<pair<int,int> >q; bool inque[maxn][maxk]; void spfa(int p) { for(int i=0;i<=n;i++) { for(int j=0;j<=k;j++) { dist[i][j]=LLONG_MAX; } } dist[p][0]=0; q.push({p,0}); inque[p][0]=true; while(!q.empty()) { int now=q.front().first; int kkk=q.front().second; q.pop(); inque[now][kkk]=false; int t=dist[now][kkk]; for(int i=fir[now];i;i=ed[i].next) { int v=ed[i].v; int a=ed[i].a; if(t>=a){ if(dist[v][(t+1)%k]>t+1) { dist[v][(t+1)%k]=t+1; if(!inque[v][(t+1)%k]) { q.push({v,(t+1)%k}); inque[v][(t+1)%k]=true; } } } else{ int w=((a-t+k-1)/k)*k+t; if(dist[v][(w+1)%k]>w+1) { dist[v][(w+1)%k]=w+1; if(!inque[v][(w+1)%k]) { q.push({v,(w+1)%k}); inque[v][(w+1)%k]=true; } } } } } } signed main() { n=read(),m=read(),k=read(); //cin>>n>>m>>k; for(int i=1;i<=m;i++) { int u,v,a; u=read(),v=read(),a=read(); //cin>>u>>v>>a; add_edge(u,v,a); } spfa(1); if(dist[n][0]==LLONG_MAX) cout<<-1<<endl; else cout<<dist[n][0]<<endl; return 0; }
后记:
好难的一道题啊。。。我太弱了qwq
离正解就差了一个 DP。。加上一维就AC啦!
鬼知道这东西出来的时候我有多开心。。
希望csp_j 2024 rp++ !!!
最优解第六页寄!(SPFA怎么你了)我看谁还说它s了,它可救过我的命啊
要没有它我说不定就 AFO 了 TAT
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战