【HDOJ6071】Lazy Running(同餘最短路思想)

傳送門

  • 題目:
    四個點1,2,3,41,2,3,4順序連成環,給定相鄰兩點間的距離,問從22號點出發再回到22號點的所有路徑中,路徑長度不小於kk的最小值。輸出這個最小值。1k1e181≤k≤1e18
  • 思路:
    主要用到同餘的思想。
    w=min(dis12,dis23)w=min(dis_{12},dis_{23})對於222\rightarrow2的一條路徑,記其路徑長度爲lenlen,那麼len+k2wlen+k*2w(k0)(k≥0)對應的路徑也是一種合法路徑,這些合法路徑長度根據%2w\%2w的值將其分爲2w2w組,並且求出每個同餘類ii對應的最短的合法路徑的長度mlen[i]mlen[i]
    mlen[i]mlen[i]表示從222\rightarrow2的合法路徑中(路徑長度爲len),滿足len%(2w)=ilen\%(2w)=i的最小的lenlen值。
    對於每個同餘類ii,如果mlen[i]kmlen[i]≥k那麼更新答案,否則,在mlen[i]mlen[i]的基礎上累加2w2w,直至滿足長度k≥k,再更新答案。
    那麼怎麼獲得mlen[]mlen[]數組呢,可以暴搜,也可以用spfa做。
    用spfa做的話dis[i][j]dis[i][j]表示從22出發到達ii滿足%(2w)=j\%(2w)=j的最小長度。隊列裏存上一個點距離當前點最短距離,初始化存入{2,02,0}。
  • ac代碼:
#include <iostream>
#include <vector>
#include <limits.h>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 6e4+10;
struct Edge{
    int nxt; ll val;
};
struct node{
    int now; ll v;
};
vector<Edge> edge[5];
queue<node> q;
int t;
ll d12, d23, d34, d41, w, k, dis[5][maxn];
void spfa()
{
    for(int i = 0; i <= 4; i++)
        for(int j = 0; j < w; j++)
            dis[i][j] = LLONG_MAX;
    q.push({2, 0});
    while(!q.empty())
    {
        int now = q.front().now; ll v = q.front().v; q.pop();
        for(auto e: edge[now])
        {
            ll tmp = v+e.val;
            if(dis[e.nxt][tmp%w]>tmp)
            {
                dis[e.nxt][tmp%w] = tmp;
                q.push({e.nxt, tmp});
            }
        }
    }
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    scanf("%d", &t);
    while(t--)
    {
        scanf("%lld %lld %lld %lld %lld", &k, &d12, &d23, &d34, &d41);
        w = 2*min(d12, d23);
        edge[1].push_back({2, d12}); edge[2].push_back({1, d12});
        edge[2].push_back({3, d23}); edge[3].push_back({2, d23});
        edge[3].push_back({4, d34}); edge[4].push_back({3, d34});
        edge[4].push_back({1, d41}); edge[1].push_back({4, d41});
        spfa();
        ll ans = LLONG_MAX;
        for(int i = 0; i < w; i++)
        {
            if(dis[2][i]>=k) ans = min(ans, dis[2][i]);
            else
            {
                ll sub = k-dis[2][i];
                ll p = sub%w==0 ? sub : (sub/w+1)*w;
                ans = min(ans, dis[2][i]+p);
            }
        }
        printf("%lld\n", ans);
        for(int i = 1; i <= 4; i++) edge[i].clear();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章