【YbtOJ#20078】路径之和

题目

题目链接:http://noip.ybtoj.com.cn/problem/20078

思路

考虑 Floyd 算法的实质:\(f[k][i][j]\) 表示只经过 \(1\sim k\) 的点时,\(i\)\(j\) 的最短路。
发现第一维的枚举顺序其实可以是任意的。所以考虑分治。
对于目前分治到的区间 \([l,r]\),我们先计算 \([l,mid]\) 的贡献,继续分治 \((mid,r]\);清空贡献后计算 \((mid,r]\) 的贡献,分治计算 \([l,mid]\)
\(l=r\) 时,除了 \(l\) 以外的所有点贡献都计算过了。直接枚举端点计算答案即可。
时间复杂度 \(O(n^3\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=330,LG=10,Inf=1e9;
int n,dis[LG][N][N];
ll ans;

void solve(int l,int r,int dep)
{
	if (l==r)
	{
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				if (i!=l && j!=l)
					ans+=(dis[dep][i][j]<Inf ? dis[dep][i][j] : -1);
		return;
	}
	int mid=(l+r)>>1;
	memcpy(dis[dep+1],dis[dep],sizeof(dis[dep]));
	for (int k=l;k<=mid;k++)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				if (i!=j && j!=k && i!=k)
					dis[dep+1][i][j]=min(dis[dep+1][i][j],dis[dep+1][i][k]+dis[dep+1][k][j]);
	solve(mid+1,r,dep+1);
	memcpy(dis[dep+1],dis[dep],sizeof(dis[dep]));
	for (int k=mid+1;k<=r;k++)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				if (i!=j && j!=k && i!=k)
					dis[dep+1][i][j]=min(dis[dep+1][i][j],dis[dep+1][i][k]+dis[dep+1][k][j]);
	solve(l,mid,dep+1);
}

int main()
{
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
		{
			scanf("%d",&dis[0][i][j]);
			if (dis[0][i][j]==-1) dis[0][i][j]=Inf;
		}
	solve(1,n,0);
	printf("%lld",ans);
	return 0;
}
posted @ 2020-11-02 14:51  stoorz  阅读(55)  评论(0编辑  收藏  举报