Problem Link
Description
给定
K
,d1,2,
d2,3
,
d3,4
,
d4,1
(
du,v
表示
u
到v的距离),每次可以从
i
跑到i−1或
i+1
,并且起点和终点只能
2
,每个点可以经过任意次。要求在四个点之间一直跑,直到跑过的路程大于或等于K。求满足条件的最小路程。
Solution
我们令
w=2∗min(d1,2,d2,3)
,即从2出发再返回2的最短路径。 然后我们开始跑最短路,定义
dis[i][j]
表示到达
i
点,路程模w等于
j
时的最短路程(有同学可能要问,为什么要模w呢?我在这里给出解释: 当到达2时,倘若
dis<K
,那么我们可以再走
K−dis+w−1w
次
w
,来使得总路程大于等于K,不妨令
k=K−dis+w−1w
,则最终结果为
dis+k∗w
,因此对于所有模
w
相等的dis,他们对应的最终结果都相同,只是加几个w的问题)。假如跑到的最短路已经大于等于
K
,那么可以直接更新答案了。
Code
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define M 60005
#define ll long long
using namespace std;
template <
class T>
inline void Rd(T &res){
char c;res=
0;
int k=
1;
while(c=getchar(),c<
48&&c!=
'-');
if(c==
'-'){k=-
1;c=
'0';}
do{
res=(res<<
3) (res<<
1) (c^
48);
}
while(c=getchar(),c>=
48);
res*=k;
}
template <
class T>
inline void Pt(T res){
if(res<
0){
putchar(
'-');
res=-res;
}
if(res>=
10)Pt(res/
10);
putchar(res%
10 48);
}
struct node{
int v;
ll dis;
bool operator <(
const node &tmp)
const{
return dis>tmp.dis;
}
}G[
4][
2];
int T;
ll k,ans,dis[
4][M];
int w,d[
4];
int u[]={-
1,
1};
void calc(
int x){
ans=min(ans,(k-x w-
1)/w*w x);
}
void Dijkstra(){
priority_queue<node>que;
dis[
1][
0]=
0;
que.push((node){
1,
0});
while(!que.empty()){
node q=que.top();que.pop();
int u=q.v;
ll d=q.dis;
if(dis[u][d%w]!=d)
continue;
for(
int i=
0;i<
2;i ){
node nxt=G[u][i];
nxt.dis =d;
ll tmp=dis[nxt.v][nxt.dis%w];
if(tmp==-
1||tmp>nxt.dis){
dis[nxt.v][nxt.dis%w]=nxt.dis;
if(nxt.dis>=k){
if(nxt.v==
1)ans=min(ans,nxt.dis);
continue;
}
if(nxt.v==
1)calc(nxt.dis%w);
que.push(nxt);
}
}
}
}
int main(){
Rd(T);
while(T--){
memset(dis,-
1,
sizeof(dis));
Rd(k);
for(
int i=
0;i<
4;i )Rd(d[i]);
w=min(d[
0],d[
1])<<
1;
ans=(k w-
1)/w*w;
for(
int i=
0;i<
4;i )
for(
int j=
0;j<
2;j ){
int t=(i u[j])%
4;
if(t<
0)t =
4;
if(j)G[i][j]=(node){t,d[i]};
else G[i][j]=(node){t,d[t]};
}
Dijkstra();
Pt(ans);
putchar(
'\n');
}
return 0;
}
这题用了同余的思想,就是对于同余的dis他们的最终结果一定都相同。