題目
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 的最小和是多少)
- 咋一看似乎是數論,實際上卻是通過建圖再跑個最短路巧妙解決,這個方法真的值得積累。