2017多校第4场 懒人跑步(spfa+思维题)

题目描述

在ZJU,每个学生都被要求课外跑步,并且需要跑够一定的距离 ,否则体育课会挂科。

ZJU有4个打卡点,分别标记为 p1,p2,p3,p4 。每次你到达一个打卡点,你只需要刷一下卡,系统会自动计算这个打卡点和上一个打卡点的距离,并将它计入你的已跑距离。

系统把这4个打卡点看成一个环。 p1 与 p2 相邻、 p2 与 p3 相邻、 p3 与 p4 相邻、 p4 与 p1 相邻。当你到达打卡点 pi 时,你只能跑到与该打卡点相邻的打卡点打卡。

打卡点 p2 是离宿舍最近的一个打卡点。CJB总是从 p2 出发,并回到 p2 。因为CJB很圆,所以他希望他跑的距离不少于 K ,但又要尽量小。

题解

取 d=min(dis1-2,dis2-3),那么对于每种方案,均可以通过往返跑 d 这条边使得距离增加 2d

令 w=2d,dp[i][j] 表示从起点出发到达 i ,距离模 w 为 j 时的最短路,这个由 spfa 可求得,时间复杂度为 O(w logw)

最后,我们由 dp[p2][j] 即可求出最优路线(具体见图)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
int t,w,d[4],inque[4][60001];
ll k,dp[4][60001];
struct que{int p,m;};
queue<que> q;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld%d%d%d%d",&k,&d[0],&d[1],&d[2],&d[3]);
        w=2*min(d[0],d[1]);
        memset(dp,0x7f,sizeof(dp));
        dp[1][0]=0;
        q.push((que){1,0});
        inque[1][0]=1;
        while(!q.empty()){
            int p=q.front().p;
            int m=q.front().m;
            int nxt=(p+1)%4;
            int pre=(p+3)%4;
            q.pop();
            inque[p][m]=false;
            if(dp[p][m]+d[p]<dp[nxt][(m+d[p])%w]){
                dp[nxt][(m+d[p])%w]=dp[p][m]+d[p];
                if(!inque[nxt][(m+d[p])%w]){
                    q.push((que){nxt,(m+d[p])%w});
                    inque[nxt][(m+d[p])%w]=1;
                }
            }
            if(dp[p][m]+d[pre]<dp[pre][(m+d[pre])%w]){
                dp[pre][(m+d[pre])%w]=dp[p][m]+d[pre];
                if(!inque[pre][(m+d[pre])%w]){
                    q.push((que){pre,(m+d[pre])%w});
                    inque[pre][(m+d[pre])%w]=1;
                }
            }
        }
        while(dp[1][k%w]>k)k++;
        printf("%lld\n",k);
    }
    return 0;
}

 

posted @ 2019-08-15 15:58  Mistletoes  阅读(127)  评论(0编辑  收藏  举报