1. 程式人生 > >HDU-6331 Problem M. Walking Plan(分塊+最短路)

HDU-6331 Problem M. Walking Plan(分塊+最短路)

Problem M. Walking Plan

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 169    Accepted Submission(s): 40

 

Problem Description

There are n intersections in Bytetown, connected with m one way streets. Little Q likes sport walking very much, he plans to walk for q days. On the i-th day, Little Q plans to start walking at the si-th intersection, walk through at least ki streets and finally return to the ti-th intersection.
Little Q's smart phone will record his walking route. Compared to stay healthy, Little Q cares the statistics more. So he wants to minimize the total walking length of each day. Please write a program to help him find the best route.

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.
In each test case, there are 2 integers n,m(2≤n≤50,1≤m≤10000) in the first line, denoting the number of intersections and one way streets.
In the next m lines, each line contains 3 integers ui,vi,wi(1≤ui,vi≤n,ui≠vi,1≤wi≤10000), denoting a one way street from the intersection ui to vi, and the length of it is wi.
Then in the next line, there is an integer q(1≤q≤100000), denoting the number of days.
In the next q lines, each line contains 3 integers si,ti,ki(1≤si,ti≤n,1≤ki≤10000), describing the walking plan.

Output

For each walking plan, print a single line containing an integer, denoting the minimum total walking length. If there is no solution, please print -1.

Sample Input

2 3 3 1 2 1 2 3 10 3 1 100 3 1 1 1 1 2 1 1 3 1 2 1 1 2 1 1 2 1 1

Sample Output

111 1 11 -1

題意:一個有向圖,有q次詢問:從s到t至少走k步需要的最短距離是多少

題解:因為n很小,可以考慮floyd。首先想到k層最短路,可是k最大值為10000,於是想到倍增的寫法,然而發現一次詢問最小的複雜度也是O(n^2*logk)。

考慮用分塊。

mp[k][i][j]為從i走到j恰好走k步的最小距離,mp[k][i][j] = min(mp[k-1][i][p] + mp[1][p][j])。

E[k][i][j]為從i走到j恰好走k*100步的最小距離,E[k][i][j] = min(E[k-1][i][p] + E[1][p][j])。

每次查詢的時候,列舉中間點,ans = min(E[k/100][u][x] + mp[k%100][x][v])

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'<<endl
#define FIN freopen("in.txt","r",stdin);
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 55;
int T, n, m;
int mp[MX * 2][MX][MX], E[MX * 2][MX][MX];
int d[MX][MX], t[MX][MX];

void mul (int a[MX][MX], int b[MX][MX], int c[MX][MX]) {
    rep (i, 1, n + 1) rep (j, 1, n + 1) t[i][j] = INF;
    rep (i, 1, n + 1) rep (j, 1, n + 1) rep (k, 1, n + 1) t[i][j] = min (t[i][j], a[i][k] + b[k][j]);
    rep (i, 1, n + 1) rep (j, 1, n + 1) c[i][j] = min (c[i][j], t[i][j]);
}

int main() {
    //FIN;
    cin >> T;
    while (T--) {
        scanf ("%d%d", &n, &m);
        rep (k, 0, 101) rep (i, 1, n + 1) rep (j, 1, n + 1) mp[k][i][j] = E[k][i][j] = INF;
        rep (i, 1, n + 1) mp[0][i][i] = E[0][i][i] = 0;
        rep (i, 0, m) {
            int u, v, w;
            scanf ("%d%d%d", &u, &v, &w);
            mp[1][u][v] = min (mp[1][u][v], w);
        }
        rep (i, 1, n + 1) rep (j, 1, n + 1) d[i][j] = mp[1][i][j];
        rep (k, 1, n + 1) rep (i, 1, n + 1) rep (j, 1, n + 1) d[i][j] = min (d[i][j], d[i][k] + d[k][j]);
        rep (x, 2, 101) mul (mp[x - 1], mp[1], mp[x]);
        rep (x, 1, 101) mul (E[x - 1], mp[100], E[x]);
        //一定要加上這句,因為有可能不能剛好100*x步到達終點
        rep (x, 0, 101) mul (E[x], d, E[x]);
        per (k, 100, 0) rep (i, 1, n + 1) rep (j, 1, n + 1) mp[k][i][j] = min (mp[k][i][j], mp[k + 1][i][j]);
        int u, v, k, q;
        scanf ("%d", &q);
        while (q--) {
            scanf ("%d%d%d", &u, &v, &k);
            int a = k / 100, b = k % 100;
            int ans = INF;
            rep (x, 1, n + 1) ans = min (ans, mp[b][u][x] + E[a][x][v]);
            printf ("%d\n", ans == INF ? -1 : ans);
        }
    }
    return 0;
}