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;
}