给你一个4个点的环,问你从2号点出发, 再回到2号点,长度>=K的最短路是多少。环上的边长度不超过30000。
跑出来所有dis(2,j)以后,然后for一遍j,根据dis(2,j)+t*2*w>=K,解出来对于每个j而言最小的t,然后尝试更新答案即可。如果dis(2,j)已经大于等于K了,那直接用其尝试更新答案。
跟CDOJ1633很像。
#include<cstdio> #include<queue> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; ll ans,K; int W,T,a[4]; typedef pair<int,int> Point; queue<Point>q; bool inq[4][60010]; int dis[4][60010]; void spfa() { memset(dis,0x7f,sizeof(dis)); memset(inq,0,sizeof(inq)); q.push(make_pair(1,0)); inq[1][0]=1; dis[1][0]=0; while(!q.empty()){ Point U=q.front(); Point V=make_pair((U.first+1)%4,(U.second+a[U.first])%(2*W)); if(dis[V.first][V.second]>dis[U.first][U.second]+a[U.first]){ dis[V.first][V.second]=dis[U.first][U.second]+a[U.first]; if(!inq[V.first][V.second]){ q.push(V); inq[V.first][V.second]=1; } } V=make_pair((U.first+3)%4,(U.second+a[(U.first+3)%4])%(2*W)); if(dis[V.first][V.second]>dis[U.first][U.second]+a[(U.first+3)%4]){ dis[V.first][V.second]=dis[U.first][U.second]+a[(U.first+3)%4]; if(!inq[V.first][V.second]){ q.push(V); inq[V.first][V.second]=1; } } q.pop(); inq[U.first][U.second]=0; } } int main(){ // freopen("1005.in","r",stdin); // freopen("1005.out","w",stdout); scanf("%d",&T); for(;T;--T){ ans=9000000000000000000ll; scanf("%lld",&K); for(int i=0;i<4;++i){ scanf("%d",&a[i]); } W=min(a[1],a[0]); spfa(); for(int i=0;i<2*W;++i){ if(dis[1][i]<2000000000){ // printf("%d: (%d) ",i,dis[1][i]); if(dis[1][i]<K){ ans=min(ans,(ll)dis[1][i]+(ll)(2*W)*((K-(ll)dis[1][i])/(ll)(2*W)+(ll)((K-(ll)dis[1][i])%(ll)(2*W)!=0))); } else{ ans=min(ans,(ll)dis[1][i]); } } } printf("%lld ",ans); } return 0; }