题解 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!

posted @ 2022-02-09 16:33  Legitimity  阅读(65)  评论(0编辑  收藏  举报