GalaxyOJ-988 (套路建图+最短路)

题目

HDU阳光长跑
题目描述
数据范围

分析

题解

程序

#include <cstdio>
#include <algorithm>
#include <cstring>
#define Add(x,y,z) (to[++num]=head[x],head[x]=num,V[num]=y,W[num]=z)
#define For(x) for(ll h=head[x],o=V[h],w=W[h]; h; o=V[h=to[h]],w=W[h])
using namespace std;
typedef long long ll;
ll head[5],to[10],V[10],W[10],num;
ll dis[5][60005];           //dis[i][j] 从2开始到 i 路径长模为 j 的最短路径 
ll d12,d23,d34,d41,K,Ha,k,l,r,f[5][60005],ans=9223372036854775807ll;
struct zzk{int x,v;} q[1000000];
void SPFA(){
    memset(dis,0x7f7f7f7f,sizeof(dis));
    dis[2][0]=0,f[2][0]=0;
    for (q[l=r=0]=(zzk){2,0}; l<=r; l++){
        For(q[l].x) if (dis[o][(q[l].v+w)%Ha]>dis[q[l].x][q[l].v]+w){
            dis[o][(q[l].v+w)%Ha]=dis[q[l].x][q[l].v]+w;
            if (!f[o][(q[l].v+w)%Ha]){
                q[++r]=(zzk){o,(q[l].v+w)%Ha};
                f[o][(q[l].v+w)%Ha]=1;
            }
        }
        f[q[l].x][q[l].v]=0;
    }
}

void debug(){
    for (ll i=1; i<=4; i++) {
        For(i) printf("(%d %d) ",o,w);
        puts("");
    }
}

int main(){
    scanf("%lld%lld%lld%lld%lld",&K,&d12,&d23,&d34,&d41);
    Add(1,2,d12),Add(2,1,d12),Add(2,3,d23),Add(3,2,d23),Add(3,4,d34),Add(4,3,d34),Add(4,1,d41),Add(1,4,d41);
    Ha=min(d12,d23)*2;
    SPFA();
    for (ll i=0; i<Ha; i++){
        k=dis[2][i];
        if (k>K) {ans=min(k,ans); continue;}
        k+=(K-k)/Ha*Ha;
        if (k<K) k+=Ha;
        ans=min(k,ans);
    }
    printf("%lld",ans);
}

提示

  • 这是一种经典的套路题,(给几种数,问凑成不小于 K 的最小和是多少)
  • 咋一看似乎是数论,实际上却是通过建图再跑个最短路巧妙解决,这个方法真的值得积累。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值