题解 SP3763 GEORGE
Posted 枫のDark
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 SP3763 GEORGE相关的知识,希望对你有一定的参考价值。
不扯闲话了
进入正题
伟大的 \\(cpp\\) 告诉我们,拿到题目一定要看一眼数据范围。于是我们先来看一下点数和边数。发现\\(n\\le10^3\\) ,\\(m\\le10^4\\),基本就是一个稠密图,而且点数不多,于是我们可以选择使用邻接矩阵来存图。
然后来考虑 \\(Luka\\) 应该怎么走。显然应该让 \\(T\\) 先生先走,于是我们考虑记录每条路的封锁时间。
int tt=0;
F(i,1,g-1) {
t[c[i]][c[i+1]]=t[c[i+1]][c[i]]=tt;
//考虑其是双向边,应当将其反向再记录一遍
//t[i][j]表示从路口i到路口j这一段路的管制开始时刻
tt+=f[c[i]][c[i+1]];//tt记录当前时刻
}
然后我们用 \\(Dijkstra\\) 跑一遍最短路即可。
细节见代码(稍微用了一点点宏):
#include<bits/stdc++.h>
#define rd(n) scanf("%d",&n);
#define F(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
const int N=1e3+10;
int n,m,a,b,k,g,f[N][N];
int c[N],t[N][N],dis[N];
bool vis[N];
struct P {
int d,t;//d表示节点的编号,t表示到达该点的时间
bool operator <(const P&a)const {
return t>a.t;
}
};
int drive(int u,int v) {
if(dis[u]>=t[u][v]&&dis[u]<=t[u][v]+f[u][v]-1) {
/*当到达时间恰好为管制时间
最小时间为T先生到达时刻加上两倍过路时间
(T先生过路的时间加上Luka过路的时间,恰好为两倍。)
*/
return (f[u][v]<<1)+t[u][v];
}
return dis[u]+f[u][v];//否则就直接加过路需要的时间
}
void Dij() {
memset(dis,0x3f,sizeof(dis));//初始化为较大值
dis[a]=k;
priority_queue<P>q;//堆优化
q.push({a,k});//从点a开始,时刻为k
while(!q.empty()) {
P t=q.top();
q.pop();
if(vis[t.d])continue;
vis[t.d]=1;
F(i,1,n) {
if(f[t.d][i]) { //t.d与i之间存在一条边
int pos=drive(t.d,i);//计算到达i点的最短时间
if(dis[i]>pos) {//松弛操作
dis[i]=pos;
q.push({i,dis[i]});
}
}
}
}
}
int main() {
rd(n)rd(m)rd(a)rd(b)rd(k)rd(g)
F(i,1,g)rd(c[i])//c是过路所需时间
int u,v,w;
F(i,1,m) {//邻接矩阵存图
rd(u)rd(v)rd(w)
f[u][v]=w;//双向边
f[v][u]=w;
}
int tt=0;
F(i,1,g-1) {
t[c[i]][c[i+1]]=t[c[i+1]][c[i]]=tt;
//考虑其是双向边,应当将其反向再记录一遍
//t[i][j]表示从路口i到路口j这一段路的管制开始时刻
tt+=f[c[i]][c[i+1]];//tt记录当前时刻
}
Dij();
printf("%d",dis[b]-k);//开车时间应当减去k
return 0;
}
声明:部分思路参考同机房巨佬
完结撒花!
以上是关于题解 SP3763 GEORGE的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #267 (Div. 2) C. George and Job