有一個徹底圖,邊有邊權。dom
對於每一個 \(i\),求一棵生成樹,使得( \(\sum_{j=1,j\neq i}^n\) \(j\) 到 \(i\) 的路徑上邊權最小值) 最小。spa
\(n\leq 2000,W\leq {10}^9\)code
記最小的邊權 \(w\),這條邊的一個端點爲 \(s\)。get
那麼 \(i\) 號點對應的生成樹就是從 \(i\) 到 \(s\) 的一條路徑,而後通過邊權最小的邊,再連向全部點。string
能夠發現 \(i\) 到 \(s\) 的路徑上除了最後一條邊以外的邊權是遞減的。並且每條邊的邊權 \(<\) 後面全部邊(除了最後一條邊)的邊權和。因此深度會 \(\leq O(\log W)\)。it
直接從每一個點開始跑最短路就能夠作到 \(O(n^2\log W)\) 。io
從 \(s\) 開始向每一個點跑最短路就能夠在 \(O(n^2)\) 內解決這道題了。function
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #include<functional> #include<cmath> #include<vector> #include<assert.h> //using namespace std; using std::min; using std::max; using std::swap; using std::sort; using std::reverse; using std::random_shuffle; using std::lower_bound; using std::upper_bound; using std::unique; using std::vector; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef std::pair<int,int> pii; typedef std::pair<ll,ll> pll; void open(const char *s){ #ifndef ONLINE_JUDGE char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } void open2(const char *s){ #ifdef DEBUG char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;} void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');} int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;} int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;} const int N=2010; int a[N][N]; int b[N]; ll s[N]; int n; int mi[N]; int main() { open("a"); n=rd(); int w=0x7fffffff,t; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) a[i][j]=a[j][i]=rd(); for(int i=1;i<=n;i++) mi[i]=0x7fffffff; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(j!=i) mi[i]=min(mi[i],a[i][j]); for(int i=1;i<=n;i++) if(mi[i]<w) { w=mi[i]; t=i; } b[t]=1; s[t]=0; for(int i=1;i<=n;i++) if(i!=t) s[i]=min(a[t][i]-w,2*mi[i]-2*w); for(int i=1;i<n;i++) { int x=0; for(int j=1;j<=n;j++) if(!b[j]&&(!x||s[j]<s[x])) x=j; b[x]=1; for(int k=1;k<=n;k++) if(!b[k]) s[k]=min(s[k],s[x]+a[x][k]-w); } for(int i=1;i<=n;i++) printf("%lld\n",s[i]+(ll)(n-1)*w); return 0; }