HDU 6071 Lazy Running(最短路)

 

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6071

 

【题目大意】

  给出四个点1,2,3,4,1和2,2和3,3和4,4和1 之间有路相连,
  现在从2点出发,最后回到2点,要求路径大于等于K,问路径长度最短是多少

 

【题解】

  取一条与2相连的权值最小的边w。
  若存在一条从起点到终点的长度为k的路径,
  那么必然存在一条长度为k+2w的路径,只要一开始在那条边上往返走就好了。
  设dij表示从起点到i,路径长度模2w为j时,路径长度的最小值。
  用最短路算法求出所有dij,然后检查d[n][k%2w]是否不超过k即可。
  对于求大于等于k的最小解,只要枚举W解不等式即可。

 

【代码】

#include <cstdio>  
#include <cstring> 
#include <queue> 
#include <utility>
#include <algorithm> 
using namespace std;
typedef long long LL;  
const int N=1000010;  
const LL INF=0x3f3f3f3f3f3f3f3f;  
typedef pair<LL,int>seg;  
priority_queue<seg,vector<seg>,greater<seg> >q;     
int head[N],u[N],v[N],w[N],nxt[N],n,m,ed=0; 
LL d[5][N],W;
void add(int a,int b,int c){  
    u[++ed]=a,v[ed]=b,w[ed]=c;
    nxt[ed]=head[u[ed]]; head[u[ed]]=ed;     
}     
void Dijkstra(int src){    
    for(int i=0;i<=n;i++)for(int j=0;j<W;j++)d[i][j]=INF;    
    q.push(make_pair(0,src));  
    while(!q.empty()){  
        seg now=q.top(); q.pop();  
        LL _w=now.first;
        int x=now.second;  
        if(_w>d[x][_w%W])continue;  
        for(int e=head[x];e!=-1;e=nxt[e]){ 
            LL nw=_w+w[e];
            if(d[v[e]][nw%W]>nw){  
                d[v[e]][nw%W]=nw;  
                q.push(make_pair(nw,v[e]));  
            }    
        }
    }
}    
int T; 
LL k,d1,d2,d3,d4;
int main(){
    scanf("%d",&T); n=4;
    while(T--){
        LL ans=INF;
        memset(head,-1,sizeof(head));ed=0;
        scanf("%lld%lld%lld%lld%lld",&k,&d1,&d2,&d3,&d4);
        if(d2<d1)W=2*d2; else W=2*d1;
        add(3,4,d3); add(4,3,d3);
        add(2,1,d1); add(1,2,d1);
        add(2,3,d2); add(3,2,d2);
        add(1,4,d4); add(4,1,d4);
        Dijkstra(2);
        for(int i=0;i<W;i++){
            if(k<=d[2][i])ans=min(ans,d[2][i]);
            else ans=min(ans,d[2][i]+((k-d[2][i]+W-1)/W)*W);
        }printf("%lld\n",ans);
    }return 0;
}
posted @ 2017-08-05 13:06  forever97  阅读(679)  评论(0编辑  收藏  举报