[USACO07NOV] Cow Relays
阿新 • • 發佈:2018-08-07
法則 http || nbsp inf gist turn 得到 成了 $ \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條邊的。其本質依然是矩陣乘法快速冪。只不過自乘變為了“自加”的形式
傳送門:>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$經過一條邊的最短路。因此當我們做矩陣乘法時,將
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