题目: 四个点
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4顺序连成环,给定相邻两点间的距离,问从
2
2
2号点出发再回到
2
2
2号点的所有路径中,路径长度不小于
k
k
k的最小值。输出这个最小值。
1
≤
k
≤
1
e
18
1≤k≤1e18
1≤k≤1e18
思路: 主要用到同余的思想。 记
w
=
m
i
n
(
d
i
s
12
,
d
i
s
23
)
w=min(dis_{12},dis_{23})
w=min(dis12,dis23)对于
2
→
2
2\rightarrow2
2→2的一条路径,记其路径长度为
l
e
n
len
len,那么
l
e
n
+
k
∗
2
w
len+k*2w
len+k∗2w,
(
k
≥
0
)
(k≥0)
(k≥0)对应的路径也是一种合法路径,这些合法路径长度根据
%
2
w
\%2w
%2w的值将其分为
2
w
2w
2w组,并且求出每个同余类
i
i
i对应的最短的合法路径的长度
m
l
e
n
[
i
]
mlen[i]
mlen[i]。
m
l
e
n
[
i
]
mlen[i]
mlen[i]表示从
2
→
2
2\rightarrow2
2→2的合法路径中(路径长度为len),满足
l
e
n
%
(
2
w
)
=
i
len\%(2w)=i
len%(2w)=i的最小的
l
e
n
len
len值。 对于每个同余类
i
i
i,如果
m
l
e
n
[
i
]
≥
k
mlen[i]≥k
mlen[i]≥k那么更新答案,否则,在
m
l
e
n
[
i
]
mlen[i]
mlen[i]的基础上累加
2
w
2w
2w,直至满足长度
≥
k
≥k
≥k,再更新答案。 那么怎么获得
m
l
e
n
[
]
mlen[]
mlen[]数组呢,可以暴搜,也可以用spfa做。 用spfa做的话
d
i
s
[
i
]
[
j
]
dis[i][j]
dis[i][j]表示从
2
2
2出发到达
i
i
i满足
%
(
2
w
)
=
j
\%(2w)=j
%(2w)=j的最小长度。队列里存上一个点距离当前点的最短距离,初始化存入{
2
,
0
2,0
2,0}。
ac代码:
#include<iostream>#include<vector>#include<limits.h>#include<queue>
using namespace std;typedeflonglong ll;constint maxn =6e4+10;struct Edge{int nxt; ll val;};struct node{int now; ll v;};
vector<Edge> edge[5];
queue<node> q;int t;
ll d12, d23, d34, d41, w, k, dis[5][maxn];voidspfa(){for(int i =0; i <=4; i++)for(int j =0; j < w; j++)
dis[i][j]= LLONG_MAX;
q.push({2,0});while(!q.empty()){int now = q.front().now; ll v = q.front().v; q.pop();for(auto e: edge[now]){
ll tmp = v+e.val;if(dis[e.nxt][tmp%w]>tmp){
dis[e.nxt][tmp%w]= tmp;
q.push({e.nxt, tmp});}}}}intmain(){//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);scanf("%d",&t);while(t--){scanf("%lld %lld %lld %lld %lld",&k,&d12,&d23,&d34,&d41);
w =2*min(d12, d23);
edge[1].push_back({2, d12}); edge[2].push_back({1, d12});
edge[2].push_back({3, d23}); edge[3].push_back({2, d23});
edge[3].push_back({4, d34}); edge[4].push_back({3, d34});
edge[4].push_back({1, d41}); edge[1].push_back({4, d41});spfa();
ll ans = LLONG_MAX;for(int i =0; i < w; i++){if(dis[2][i]>=k) ans =min(ans, dis[2][i]);else{
ll sub = k-dis[2][i];
ll p = sub%w==0? sub :(sub/w+1)*w;
ans =min(ans, dis[2][i]+p);}}printf("%lld\n", ans);for(int i =1; i <=4; i++) edge[i].clear();}return0;}