题目大意:
现在有4个点,我们一开始在点2处 ,我们希望最终也回到点2处 ,问我们怎样走,使得总路径和大于等于K并且最小。
思路:
我们知道,我们可以选以2为起点,1作为另一个点(或者是3的话也是相同的道理),使得我们的主人公一直徘徊在这条路径上,那么我们最终的Ans,可以表示为2*W(1,2)+Len这里Len的长度明显在区间:【0,2*W(1,2)】之间,那么我们就去跑一个同余的最短路即可。
那么我们SPFA跑最短路,处理出数组Dist【i】【Len】表示,从2出发,到点i处,长度%2*W(1,2)为Len的最短路。
那么对于结果,我们枚举区间【0,2*W(1,2)】的值作为Len,然后向上去添加 2*W(1,2)即可。
对于Dist【2】【i】,我们考虑:
如果Dist【2】【i】>=K,那么更新ans=min(ans,Dist【2】【i】);
否则我们设定Ned=K-Dist【2】【i】,表示缺少的路径长度,我们向上去添加2*W(1,2)即可,添加的长度为:Ned/2*W(1,2)*(2*W(1,2))+Ned%(2*W(1,2))==0?0:2*W(1,2)。
其内容不难理解。
注意初始化数组和INF要足够大,就没有别的什么坑点了。
Ac代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<queue> using namespace std; #define ll __int64 const ll INF=2e18; struct node { int u; ll len; } now,nex; ll mod; ll mp[5][5]; ll vis[5][70050]; ll dist[5][70050]; void SPFA() { queue<node>s; memset(vis,0,sizeof(vis)); for(int j=1; j<=4; j++) { for(int k=0; k<=70000; k++) { dist[j][k]=INF; } } dist[2][0]=0; now.u=2,now.len=0; s.push(now); while(!s.empty()) { now=s.front(); // vis[now.u][now.len%mod]=0; s.pop(); for(int v=1; v<=4; v++) { if(mp[now.u][v]!=INF) { nex.u=v; nex.len=now.len+mp[now.u][v]; if(dist[v][nex.len%mod]>now.len+mp[now.u][v]) { dist[v][nex.len%mod]=now.len+mp[now.u][v]; if(vis[v][nex.len%mod]==0) { vis[v][nex.len%mod]=1; s.push(nex); } } } } } } int main() { int t; scanf("%d",&t); while(t--) { ll K,a,b,c,d; scanf("%I64d%I64d%I64d%I64d%I64d",&K,&a,&b,&c,&d); for(int i=1; i<=4; i++) { for(int j=1; j<=4; j++) { mp[i][j]=INF; } } mp[1][2]=mp[2][1]=a; mp[2][3]=mp[3][2]=b; mp[3][4]=mp[4][3]=c; mp[4][1]=mp[1][4]=d; mod=2*mp[1][2]; SPFA(); ll ans=INF; for(int i = 0; i < mod; i++) { if(dist[2][i]>=K) { ans=min(ans,dist[2][i]); } else { ll ned=K-dist[2][i]; ll tmp; if(ned%mod==0)tmp=0; else tmp=mod; ans=min(ans,dist[2][i]+ned/mod*mod+tmp); } } printf("%I64d\n",ans); } }