HDU 6071 Lazy Running(模同余最短路)

61 篇文章 0 订阅

Description
四个点1,2,3,4围成一个圈,给出12,23,34,41之间的距离,从2出发要求跑至少k米回到2处,问最短距离
Input
第一行一整数T表示用例组数,每组用例输入四个整数d1,d2,d3,d4分别表示12,23,34,41之间的距离(1<=T<=15,1<=k<=1e18,1<=d1,d2,d3,d4<=30000)
Output
输出从2出发回到2的距离不少于k的最短距离
Sample Input
1
2000 600 650 535 380
Sample Output
2165
Solution
令m=2*min(d1,d2),如果存在一个距离为x的方案则必然存在一个距离为x+m的方案(因为从2可以跑到1或3再跑回来),考虑四个点在模m意义下的最短路,dis[i][j]表示从2出发到i点距离模m为j的最短路长度,求出最短路后,枚举j,如果dis[2][j] < k则拿m把dis[2][j]补到不小于k为止,更新答案,如果dis[2][j]>=k则直接更新答案
Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int maxn=60001;
const ll INF=2e18;
struct node
{
    int v,mw;
    ll w;
    node(){};
    node(int _v,int _mw,ll _w){v=_v,mw=_mw,w=_w;}
};
queue<node>que;
int T,d[4],mod;
ll k,dis[4][maxn];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d",&k);
        for(int i=0;i<4;i++)scanf("%d",&d[i]);
        mod=2*min(d[0],d[1]);
        for(int i=0;i<4;i++)
            for(int j=0;j<mod;j++)
                dis[i][j]=INF;
        while(!que.empty())que.pop();
        que.push(node(1,0,0));
        while(!que.empty())
        {
            node now=que.front();
            que.pop();
            int v=now.v,mw=now.mw,tv,tmw;
            ll w=now.w,tw;
            if(dis[v][mw]<w)continue;
            tv=(v+1)%4,tmw=(mw+d[v])%mod,tw=w+d[v];
            if(dis[tv][tmw]>tw)dis[tv][tmw]=tw,que.push(node(tv,tmw,tw));
            tv=(v+3)%4,tmw=(mw+d[tv])%mod,tw=w+d[tv];
            if(dis[tv][tmw]>tw)dis[tv][tmw]=tw,que.push(node(tv,tmw,tw));
        }
        ll ans=INF;
        for(int i=0;i<mod;i++)
            if(dis[1][i]<k)
            {
                ll temp=(k-dis[1][i]+mod-1)/mod*mod+dis[1][i];
                ans=min(ans,temp);
            }
            else ans=min(ans,dis[1][i]);
        printf("%I64d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值