1. 程式人生 > >[USACO07NOV] Cow Relays

[USACO07NOV] Cow Relays

法則 http || nbsp inf gist turn 得到 成了

傳送門:>Here<

題意:求在無向圖中,S到E恰好經過T條邊的最短路(邊可重復走) ($T \leq 100$)

解題思路

依然是好題。使用矩陣乘法——漸漸發現,矩陣乘法做圖論題和Floyd有著很大的聯系。從方程就能看出來相似:$f[i][k]+f[k][j]$和$f[i][k]*f[k][j]$。Floyd每次松弛一條邊,最後拼湊出一條最短路。而鄰接矩陣自乘k次相當於把自己松弛了k次——當然,和Floyd有所不同,Floyd如果無法松弛便不松弛,而矩陣乘法則會強行松弛k次,即使k次之後變成了0

這道題和上一道題不同,不再是純矩陣乘法,而是怎麽說,修改了乘法的定義。依然看鄰接矩陣,$g[i][j]$表示的是$i$到$j$經過一條邊的最短路。因此當我們做矩陣乘法時,將

$ \sum\limits_{i=1}^{cnt} g[i][k]*g[k][j] $ 改為 $Min\{ g[i][k]+g[k][j] \}$,假設得到的矩陣為b,那麽$b[i][j]$在$g$“自乘”一次以後得到的就是$i到j$恰好經過兩條邊的最短路。因此通過$g^k$就能夠求出經過k條邊的。其本質依然是矩陣乘法快速冪。只不過自乘變為了“自加”的形式

Code

註意不能夠添加判斷$if(i==j) continue$,因為即使起點終點相等,繞一圈回到自己也是一種走法(就因為這個調了一個小時……)

另外,需要增加判斷,轉移時的$a[i][k]$與$a[k][j]$不能為0,因為我們需要保證嚴格的k條邊。為0則代表那一部分不存在了……

/*By DennyQi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 10010;
const int MAXM = 27010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ - && (c < 0 || c > 9)) c = getchar(); if(c == -) w = -1, c = getchar(); while(c >= 0 && c <= 9) x = (x << 3) + (x << 1) + c - 0, c = getchar(); return x * w; } int N,T,S,E,x,y,z,cnt; int g[105][105],ans[105][105],a[105][105],b[105][105],idx[1010]; inline void Matrix_KSM(int y){ while(y > 0){ if(y & 1){ for(int i = 1; i <= cnt; ++i){ for(int j = 1; j <= cnt; ++j){ b[i][j] = INF; for(int k = 1; k <= cnt; ++k){ if(!ans[i][k] || !a[k][j]) continue; b[i][j] = Min(b[i][j], ans[i][k] + a[k][j]); } } } for(int i = 1; i <= cnt; ++i){ for(int j = 1; j <= cnt; ++j){ ans[i][j] = b[i][j]; } } } for(int i = 1; i <= cnt; ++i){ for(int j = 1; j <= cnt; ++j){ b[i][j] = INF; for(int k = 1; k <= cnt; ++k){ if(!a[i][k] || !a[k][j]) continue; b[i][j] = Min(b[i][j], a[i][k] + a[k][j]); } } } for(int i = 1; i <= cnt; ++i){ for(int j = 1; j <= cnt; ++j){ a[i][j] = b[i][j]; } } y /= 2; } } int main(){ N = r, T = r, S = r, E = r; memset(g, 0x3f, sizeof(g)); for(int i = 1; i <= T; ++i){ z = r, x = r, y = r; if(!idx[x]) idx[x] = ++cnt; if(!idx[y]) idx[y] = ++cnt; g[idx[x]][idx[y]] = Min(g[idx[x]][idx[y]],z); g[idx[y]][idx[x]] = Min(g[idx[y]][idx[x]],z); } for(int i = 1; i <= cnt; ++i){ for(int j = 1; j <= cnt; ++j){ a[i][j] = g[i][j]; ans[i][j] = g[i][j]; } } Matrix_KSM(N-1); printf("%d", ans[idx[S]][idx[E]]); return 0; }

[USACO07NOV] Cow Relays