题目: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 ",ans); } return 0; }