[USACO07NOV]牛繼電器Cow Relays
阿新 • • 發佈:2018-09-22
super turn con 倍增floyd tor 問題 實現 ace 答案
矩陣快速冪+倍增floyd
這道題十分神啊,floyd與矩陣快速冪(思想)結合。
矩陣快速冪的原理與普通快速冪一樣,因為矩陣乘法滿足交換律。
而這道題是讓我們求從s出發恰好經過k條邊(k<=1000000)到達t的最短路。如何考慮?圖有一個性質,我們令矩陣Ci j表示i j之間是否存在邊,那麽矩陣的k次冪就是任意點走過恰好k步能到達的點(值就是方案數)。利用這個思想,我們考慮floyd的實現,傳統的floyd是在一個矩陣中轉移,可以走任意步。我們改一改:
//floyd gk fina; for (int i=1;i<=tot;++i) for (int j=1;j<=tot;++j) fina.m[i][j]=INF; for (int k=1;k<=tot;++k) for (int i=1;i<=tot;++i) for (int j=1;j<=tot;++j) { fina.m[i][j]=min(fina.m[i][j],a.m[i][k]+b.m[k][j]); } return fina; //快速冪 while (k) { if (k&1) e=floyd(e,firs); firs=floyd(firs,firs); k>>=1; }
firs就是一開始的圖,e初始值除了對角線以外其余都是INF。所以第一遍只能求出恰好一遍能走到的點,第二次就能求出恰好兩步的,下一次恰好4步。。。最終倍增地求出答案.
具體實現:用走 i 步的最短路和走 j 步的最短路生成一個答案:答案就是走 i*j 步的最短路
code:
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<cstring> #include<vector> #include<stack> #define int long long #define SUPER_INT signed const int maxn=106; using namespace std; const int INF=1e17; struct gk { int m[maxn][maxn]; }; int s,t,k,m,id[6000000],tot; gk firs,ans; inline gk floyad(gk a,gk b) { gk fina; for (int i=1;i<=tot;++i) for (int j=1;j<=tot;++j) fina.m[i][j]=INF; for (int k=1;k<=tot;++k) for (int i=1;i<=tot;++i) for (int j=1;j<=tot;++j) { fina.m[i][j]=min(fina.m[i][j],a.m[i][k]+b.m[k][j]); } return fina; } gk e; inline gk fast_pow(int k) { for (int i=1;i<=tot;++i) e.m[i][i]=0; while (k) { if (k&1) e=floyad(e,firs); firs=floyad(firs,firs); k>>=1; } return e; } SUPER_INT main() { for (int i=1;i<=105;++i) for (int j=1;j<=105;++j) firs.m[i][j]=ans.m[i][j]=e.m[i][j]=INF; cin>>k>>m>>s>>t; for (int i=1,x,y,c;i<=m;++i) { scanf("%lld%lld%lld",&c,&x,&y); if (!id[x]) id[x]=++tot; if (!id[y]) id[y]=++tot; firs.m[id[x]][id[y]]=firs.m[id[y]][id[x]]=c; } gk ans=fast_pow(k); cout<<ans.m[id[s]][id[t]]; return 0; }
收獲:
矩陣類問題註意打表考慮(手算太慢了,還要記住結論:矩陣的k次冪的性質,矩陣快速冪的實現,以及floyd與矩陣具有很好的相容性。
[USACO07NOV]牛繼電器Cow Relays