题解 UVa1416 【Warfare And Logistics】(分治 floyd)
讲一种另类的做法。
第一问直接一遍 floyd
。
第二问,首先考虑暴力,枚举删掉哪条边,然后作 floyd
,时间复杂度是 \(O(n^3m)\),无法接受。
然后考虑优化,在上述暴力中,我们发现其实有很多信息被浪费了,比如由边集 \(\{1,2,3,5\}\)
构成的图和由边集 \(\{1,2,3,4\}\) 构成的图中,她们的交集 \(\{1,2,3\}\) 其实是计算了两次的,这一部分的计算是没有必要的。
在考虑一下 floyd
的过程本质:其实是对于不完整图的逐步完整化:从一开始没有点,然后逐渐向其中加点(枚举 \(k\)),然后计算新加点的贡献。
那么就完全可以计算出边集 \(\{1,2,3\}\) 的最短路信息后保存,分别枚举 \(4\) 和 \(5\) 这两条边产生的贡献,在\(\{1,2,3\}\) 的最短路信息上修改。
什么算法时候干这样的事?分治,解决小问题后在小问题的基础上解决大问题。
设 \(f(l,r)\) 表示由除 \([l,r]\) 外的边集构成的最短路信息,当 \(f(l,r)\) 计算出来后,\(f(l,mid)\) 只需要计算边 \([mid+1,r]\) 产生的贡献,在 \(f(l,r)\) 的基础上修改就可以了;\(f(mid+1,r)\) 同理。
主定理得出时间复杂度为 \(O(n^2m\log m)\) ,可以接受;空间上因为需要保存每层的信息,所以空间复杂度为 \(O(n^2\log m)\),可以接受。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rg register
#define ll long long
#define inf 0x3f3f3f3f
#define djq 998244353
#define lowbit(x) (x&(-x))
inline void file(){
freopen("P1341.in","r",stdin);
freopen("P1341.ans","w",stdout);
}
char buf[1<<21],*p1=buf,*p2=buf;
inline int getc(){
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
rg int ret=0,f=0;char ch=getc();
while(!isdigit(ch)){if(ch==EOF)exit(0);if(ch=='-')f=1;ch=getc();}
while(isdigit(ch)){ret=ret*10+ch-48;ch=getc();}
return f?-ret:ret;
}
int n,m,u[1005],v[1005];
ll l,f[21][105][105],w[1005],ans1,ans2;
inline void init(const int _n,const int _l){
ans1=ans2=0;
for(rg int i=1;i<=_n;++i){
for(rg int j=1;j<=_n;++j)
f[0][i][j]=_l;
f[0][i][i]=0;
}
}
inline void update(int kase,int l,int r){
memcpy(f[kase],f[kase-1],sizeof(f[kase]));
for(rg int k=l;k<=r;++k)
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=n;++j)
f[kase][i][j]=min(f[kase][i][j],
min(f[kase][i][u[k]]+f[kase][v[k]][j]+w[k],
f[kase][i][v[k]]+f[kase][u[k]][j]+w[k]));
}
void solve(int kase,int l,int r){
if(l==r){
rg ll now=0;
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=n;++j)
now+=f[kase][i][j];
ans2=max(ans2,now);
return;
}
const int mid=l+r>>1;
update(kase+1,l,mid);
solve(kase+1,mid+1,r);
update(kase+1,mid+1,r);
solve(kase+1,l,mid);
}
signed main(){
// file();
while(1){
n=read(),m=read(),l=read();
init(n,l);
for(rg int i=1;i<=m;++i)
u[i]=read(),v[i]=read(),w[i]=read();
update(1,1,m);
for(rg int i=1;i<=n;++i)
for(rg int j=1;j<=n;++j)
ans1+=f[1][i][j];
solve(0,1,m);
printf("%lld %lld\n",ans1,ans2);
}
return 0;
}
//To the ocean it goes,reaching you through the rivers.
//Flowerworks -mili
☆KIRA!