2016 计蒜之道 复赛 百度地图的实时路况
巧妙的解法。
首先直接限定每一个点不走跑$floyd$是$n^4$的,会超时,我们在$floyd$的时候加入分治思想,用$solve(l, r)$表示不考虑$[l, r]$区间的点所能得到的最短路,然后每一层处理一下就好了,直到最后一层就更新到答案中去。
时间复杂度$O(n^3logn)$。
我的代码在$Windows$下一运行就爆栈。
Code:
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 305; const ll inf = 0x3f3f3f3f3f3f3f3f; int n; ll ans = 0LL; struct Matrix { ll s[N][N]; inline void init() { memset(s, 0x3f, sizeof(s)); } inline ll* operator [] (const int now) { return s[now]; } }; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } template <typename T> inline void chkMin(T &x, T y) { if(y < x) x = y; } void solve(int l, int r, Matrix now) { if(l == r) { for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(i != l && j != l) ans += (now[i][j] == inf) ? -1 : now[i][j]; return; } Matrix tmp = now; int mid = ((l + r) >> 1); for(int k = mid + 1; k <= r; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) chkMin(tmp[i][j], tmp[i][k] + tmp[k][j]); solve(l, mid, tmp); tmp = now; for(int k = l; k <= mid; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) chkMin(tmp[i][j], tmp[i][k] + tmp[k][j]); solve(mid + 1, r, tmp); } int main() { read(n); Matrix a; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { read(a[i][j]); if(a[i][j] == -1) a[i][j] = inf; } /* printf("\n"); for(int i = 1; i <= n; i++, printf("\n")) for(int j = 1; j <= n; j++) printf("%lld ", a[i][j]); */ solve(1, n, a); printf("%lld\n", ans); return 0; }