题目:http://acm.hdu.edu.cn/showproblem.php?pid=6071
题意:给你4个点,1-2,2-3,3-4,4-1之间有边相连
求从2点出发,回到2点时最接近k的路径长度
取与2相连的最短边w
如果存在一条回到2的路径长度为x,那么一定存在一条长度为x+2w的路径,往返一次就行了
用d[i][j]表示,到达i 时,mod 2*w 为j 时的最短路径
用最短路算法维护这个数组即可
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
typedef pair<ll,int> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
int tot;
int mod;
int to[N],nt[N],val[N],head[N];
ll d[5][N];
void add(int u,int v,int w)
{
nt[++tot]=head[u];
to[tot]=v;
val[tot]=w;
head[u]=tot;
}
void dij(int x)
{
for(int i=1;i<=4;i++)
for(int j=0;j<mod;j++)
d[i][j]=INF;
priority_queue<pa,vector<pa>,greater<pa> > que;
que.push(make_pair(0,x));
while(!que.empty())
{
pa t=que.top();que.pop();
ll x=t.first;
int y=t.second;
if (x>d[y][x%mod]) continue;
for(int i=head[y];i!=-1;i=nt[i])
{
ll tem=x+val[i];
if (d[to[i]][tem%mod]>tem)
{
d[to[i]][tem%mod]=tem;
que.push(make_pair(tem,to[i]));
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll k;
int d1,d2,d3,d4;
scanf("%lld%d%d%d%d",&k,&d1,&d2,&d3,&d4);
if (d1>d2) mod=2*d2;else mod=2*d1;
tot=0;
memset(head,-1,sizeof(head));
add(1,2,d1);add(2,1,d1);
add(2,3,d2);add(3,2,d2);
add(3,4,d3);add(4,3,d3);
add(4,1,d4);add(1,4,d4);
dij(2);
ll ans=INF;
for(int i=0;i<mod;i++)
{
if (d[2][i]>=k) ans=min(ans,d[2][i]);
else ans=min(ans,d[2][i]+(k-d[2][i]+mod-1)/mod*mod);
}
printf("%lld\n",ans);
}
return 0;
}