Floyd算法
传送门:医院设置
基于动态规划的实现,将目前状态划分成两个状态。
那么,可不可以先循环
i
i
i和
j
j
j,然后把
k
k
k放到最外层呢?
答案是不行的,如果打乱了
i
,
j
,
k
i,j,k
i,j,k的顺序,则程序无法得出正确的结果。
可以把
k
k
k想象成一个阶段,即
k
k
k为中转点时,枚举
i
,
j
i,j
i,j,通过
k
k
k的变动不停地松弛
i
,
j
i,j
i,j之间的最短路。因为
i
,
j
i,j
i,j可以重复遍历,但
k
k
k不能。如果
k
k
k在内层循环,程序无法进行多次的松弛操作,也就是程序出错的原因。
本题参考代码
#include<bits/stdc++.h>
#define M 101
using namespace std;
int n,w[M],u[M],v[M],dp[M][M];
int main(){
scanf("%d",&n);
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d%d%d",&w[i],&u[i],&v[i]);
dp[i][i]=0;
if(u[i]>0){
dp[i][u[i]]=1;
dp[u[i]][i]=1;
}
if(v[i]>0){
dp[i][v[i]]=1;
dp[v[i]][i]=1;
}
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
long long Minn=int(1e10+1);
for(int i=1;i<=n;i++){
long long sum=0;
for(int j=1;j<=n;j++){
sum+=dp[i][j]*w[j];
if(sum>Minn)break;
}
if(Minn>sum)Minn=sum;
}
cout<<Minn<<endl;
return 0;
}