#floyd,分治#D 路徑之和
阿新 • • 發佈:2020-11-02
題目
對於每個\(y\),求除了\(y\)之外,其餘的所有點組成的有序點對\((x,z)\)
不經過\(y\)的最短路長度之和(不存在即為-1)。\(n\leq 320\)
分析
太妙了,首先用floyd樸素就是\(O(n^4)\)
由於樸素演算法有很多冗餘狀態,
考慮分治處理,\([l,r]\)表示當前區間以外進行過floyd
對於\(l=r\)的時候直接統計答案,否則拆成\([l,mid],[mid+1,r]\)
然後計算左區間對右區間和右區間對左區間的貢獻,時間複雜度\(O(n^3\log n)\)
程式碼
#include <cstdio> #include <cctype> #include <cstring> #define rr register using namespace std; const int N=321,inf=0x3f3f3f3f; int dis[10][N][N],n; long long ans; inline signed iut(){ rr int ans=0,f=1; rr char c=getchar(); while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans*f; } inline void Min(int &a,int b){a=a<b?a:b;} inline void divi(int dep,int l,int r){ if (l==r){ for (rr int i=1;i<=n;++i) for (rr int j=1;j<=n;++j) if ((i^j)&&(i^r)&&(j^r)){ if (dis[dep][i][j]^inf) ans+=dis[dep][i][j]; else --ans; } return; } rr int mid=(l+r)>>1; memcpy(dis[dep+1],dis[dep],sizeof(dis[dep])); for (rr int k=mid+1;k<=r;++k) for (rr int i=1;i<=n;++i) for (rr int j=1;j<=n;++j) if ((i^j)&&(i^k)&&(j^k)) Min(dis[dep+1][i][j],dis[dep+1][i][k]+dis[dep+1][k][j]); divi(dep+1,l,mid); memcpy(dis[dep+1],dis[dep],sizeof(dis[dep])); for (rr int k=l;k<=mid;++k) for (rr int i=1;i<=n;++i) for (rr int j=1;j<=n;++j) if ((i^j)&&(i^k)&&(j^k)) Min(dis[dep+1][i][j],dis[dep+1][i][k]+dis[dep+1][k][j]); divi(dep+1,mid+1,r); } signed main(){ freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); n=iut(); for (rr int i=1;i<=n;++i) for (rr int j=1;j<=n;++j){ dis[0][i][j]=iut(); if (dis[0][i][j]<0) dis[0][i][j]=inf; } divi(0,1,n); return !printf("%lld",ans); }