Floyd
多元最短路径
注意这个一定是松弛点在最外层循环
(上面这条如果记不住其实跑三次floyd就一定可以得出正解,但毕竟会被卡常)
这是一个耳熟能详的算法,对于每一个oier来讲应该都写过,主要的思想就是通过不断地枚举顶点去进行松弛操作,其实对于单纯的多元最短路,我们可以打dijk加枚举,或者直接bfs加枚举,复杂度都比他小,但是这个算法的作用其实是哟个思想,我们可以利用这个松弛操作的思想来干很多事,比如维护图的连通性,就有点像并查集。
这里来一道维护图的关系的例题,https://www.luogu.com.cn/problem/P2419,
题面就不说了,其实我们不难发现当一个点的入度+出度=n-1时候,这个点的位置就确定了,所以我们就可可以利用枚举中间点的思想去维护两个奶牛值之间的关系,具体代码如下
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1000][1000]={0};
int cnt[1000]={0};
void get_input(){
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
a[x][y]=1;//x胜利
cnt[x]++;
cnt[y]++;//用来记录有多少不等关系,只要有n-1条不等关系那么我们能够确定这个点的位置
}
}
void get_floyd(){
for(int k=1;k<=n;k++){//弗洛伊德一定是松弛点在最外层循环
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][k]&&a[k][j]&&!a[i][j]){//注意判断这个店要之前没有联通过,要不然cnt会多加
a[i][j]=1;
cnt[i]++;
cnt[j]++;//入度和出度这里没有必要分开
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(cnt[i]>=n-1)
ans++;
}
printf("%d",ans);
}
int main(){
get_input();
get_floyd();
return 0;
}
再来一到例题,这也是利用floyd的思想去在图上dphttps://www.luogu.com.cn/problem/P2888
***注意用临接表去存边时候,如果有重边的出现,那么一定要根据题目去改一下***这个很重要
接下来就是这道题了 其实很容易就想到做发 road[i][j]=min(road[i][j],max(road[i][k],road[k][y])) 这个要特判一下连通性,这个一想到那么就欧克了,其实在图中的问题如果发现点数<1000,就如果是100 500多,就可以想到floyd
代码如下`
#include<bits/stdc++.h>
using namespace std;
int n,m,t;
int road[1000][1000];
void get_input(){
memset(road,0x7f,sizeof(road));
scanf("%d%d%d",&n,&m,&t);
int x,y,z;
for(int i=1;i<=m;i++){
// cout<<"i"<<endl;
scanf("%d%d%d",&x,&y,&z);
road[x][y]=min(road[x][y],z);
}
}
void get_maxn(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(road[i][k]!=0x7f&&road[k][j]!=0x7f&&road[i][j]!=0x7f)
road[i][j]=min(road[i][j],max(road[i][k],road[k][j]));
}
}
}
}
void get_ans(){
int a,b;
for(int i=1;i<=t;i++){
//cout<<"i1"<<endl;
scanf("%d%d",&a,&b);
if(road[a][b]<=1000000)
printf("%d\n",road[a][b]);
else printf("-1\n");
}
}
int main(){
get_input();
get_maxn();
get_ans();
return 0;
}
Floyd的思想也可以做传递闭包,就是知道i,k&&k,j的关系,就可以知道i,j的关系,当然spfa更加可以
最小环
其实就是找一个图上的权值和最小的环,这个用这个很好做,我们知道在floyd的最外层循环中,每一次到k,就说明前面的k-1个点的最短路是已经确定的,那么我们每一次去找这个k-1个数中的i,j之后用a[i][k]+a[j][k]+dis[i][j]就是一个环的权值,注意a是原来数组,dis则是确定的最小路。