题目:
题意:
给出一张图,有形如
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)的三元组,表示从
x
x
x到
z
z
z但不经过
y
y
y的最短路长度
问所有
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)的和时多少
分析:
不经过
y
y
y,即已经尝试过除
y
y
y以外的所有点,所以我们的基本思路就可以确定为分治
y
y
y,当
l
=
r
l=r
l=r时就表示其他点都已经被试过了,可以开始统计答案
回想下
F
l
o
y
d
Floyd
Floyd,在转移的过程中的
k
k
k就是中间点,也就是会经过的点,二者结合就可以完成了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define LL long long
using namespace std;
inline LL read()
{
LL s=0,f=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {s=s*10+c-'0';c=getchar();}
return s*f;
}
LL n,f[15][325][325],ans=0;
void solve(LL l,LL r,LL dep)
{
if(l==r)
{
for(LL i=1;i<=n;i++)
for(LL j=1;j<=n;j++)
{
if(i==l||j==l) continue;
ans+=(f[dep][i][j]==2147483647/3)?-1:f[dep][i][j];
}
return;
}
LL mid=(l+r)>>1;
memcpy(f[dep+1],f[dep],sizeof(f[dep]));
for(LL k=l;k<=mid;k++)
for(LL i=1;i<=n;i++)
for(LL j=1;j<=n;j++)
f[dep+1][i][j]=min(f[dep+1][i][j],f[dep+1][i][k]+f[dep+1][k][j]);
solve(mid+1,r,dep+1);
memcpy(f[dep+1],f[dep],sizeof(f[dep]));
for(LL k=mid+1;k<=r;k++)
for(LL i=1;i<=n;i++)
for(LL j=1;j<=n;j++)
f[dep+1][i][j]=min(f[dep+1][i][j],f[dep+1][i][k]+f[dep+1][k][j]);
solve(l,mid,dep+1);
return;
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
n=read();
for(LL i=1;i<=n;i++)
for(LL j=1;j<=n;j++)
{
LL x=read();
f[0][i][j]=(x==-1?2147483647/3:x);
}
solve(1,n,0);
cout<<ans;
return 0;
}