HDU 6071 Lazy Running

来源:互联网 发布:淘宝上的秒杀快吗 编辑:程序博客网 时间:2024/05/19 18:14
  • 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6071

  • 题意:

    • 环上有4个点,给定相邻点的距离,找一条以2号点起止的路径,使总长度大于K,求路径的最小长度。
  • 规模:

    • T(1≤T≤15)
    • K,d1,2,d2,3,d3,4,d4,1(1≤K≤10^18,1≤d≤30000)
  • 类型:

    • DP
  • 分析:

    • 初看题目,应该是一个DP问题,DP[i][j],i为当前节点编号,j为当前已走长度,那么转移方程是很好写的。
    • 但是对于这道题,K太大了,状态数太多。考虑优化;
    • 取w=min(d_{1,2},d_{2,3}),那么对于每一种方案,均可以通过往返跑w这条边使得距离增加2w。也就是说,如果存在距离为k的方案,那么必然存在距离为k+2w的方案。
    • 这个2w其实是跑一圈的最短长度;
    • 这个时候考虑K,2w同余系,如果vis[1][i]==false,即任意跑法都不能得到长度(i+2w),舍去
    • 需要记录能够i的最小dis;
  • 时间复杂度&&优化:

    • O(4*2*d)
  • 代码:

#include <bits/stdc++.h>using namespace std;const int MAXN=70000;const int INF=0x3fff3fff;typedef long long ll;using namespace std;ll K;int x1,x2,x3,x4;bool vis[5][MAXN];ll dis[5][MAXN];struct node{    int pos;    int dis;    node(int _pos=0,int _dis=0):pos(_pos),dis(_dis){}};int edge[4][4];void init(){    memset(edge,-1,sizeof(edge));}ll DP(ll MOD){    memset(vis,false,sizeof(vis));    memset(dis,0,sizeof(dis));    queue<node > q;    while(!q.empty())q.pop();    q.push(node(1,0));    vis[1][0]=true;    while(!q.empty()){        node tmp=q.front();q.pop();//        cout<<tmp.pos<<"    "<<dis[tmp.pos][tmp.dis]<<endl;        node next;        for(int i=0;i<4;i++){            if(edge[tmp.pos][i]==-1)continue;            next.pos=i;            next.dis=(tmp.dis+edge[tmp.pos][i])%MOD;            if(!vis[next.pos][next.dis]||dis[next.pos][next.dis]>dis[tmp.pos][tmp.dis]+edge[tmp.pos][i]){                vis[next.pos][next.dis]=true;                dis[next.pos][next.dis]=dis[tmp.pos][tmp.dis]+edge[tmp.pos][i];                //dis[next.pos][next.dis]=(max((ll)0,K-next.dis-1)/MOD +1)*MOD+next.dis;                q.push(next);            }        }    }    ll x,y,ret=-1;    for(int i=0;i<MOD;i++){        if(vis[1][i]==true){            x=dis[1][i];            if(x>=K)y=x;            else {                y=((K-x-1)/MOD+1)*MOD+x;            }            ret==-1?ret=y:ret=min(ret,y);        }    }    return ret;}int main(){    int T;    scanf("%d",&T);    while(T--){        init();        scanf("%I64d%d%d%d%d",&K,&edge[0][1],&edge[1][2],&edge[2][3],&edge[3][0]);        edge[1][0]=edge[0][1];        edge[2][1]=edge[1][2];        edge[3][2]=edge[2][3];        edge[0][3]=edge[3][0];        ll MOD=min(2*edge[0][1],2*edge[1][2]);        printf("%I64d\n",DP(MOD));    }    return 0;}