此笔记开始记录时间为2019.7.20
主要供自己深化知识点
一、Floyd算法:
流程(重点理解):
通常我们写的Floyd算法框架是这样的
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
Floyd算法能如此优美是由于其为dp算法
式子如此简单以至于我们能轻而易举将其背下
大部分人对其了解只限于——三重循环 k 放最外层 i j 放内层
但是这个算法并不是这么的显然
首先
说这是个dp算法
因为存在转移方程——d[i][j]=min(d[i][j],d[i][k]+d[k][j])可以感性理解一下:对不起我太菜了
稍稍证明一下:
设d[i][j][k]为i->j路径只经过1-k节点的最短路
且d[i][j][0]为i->j的初始路径
则若经过k节点
d[i][j][k]=d[i][k][k-1]+d[k][j][k-1]
否则
d[i][j][k]=d[i][j][k-1]
最后滚动数组就可以得出最终式了
用法总结:
最短路:最基本用法,套框架即可
传递闭包:
通过Floyd确定各两者的二元关系
经典例题:POJ3660 Cow Contest
题目大意:有N头牛,评以N个等级,各不相同,先给出部分牛的等级的高低关系,问最多能确定多少头牛的等级
解题思路:一头牛的等级,当且仅当它与其它N-1头牛的关系确定时确定,于是我们可以将牛的等级关系看做一张有向图,然后跑Floyd,得到任意两点的关系,再对每一头牛进行检查即可无向图最小环:
运用Floyd求无向图中的最小环
例题:POJ1734 Sightseeing trip
题目大意:给一张图,求图中长度最小的环,输出环中节点
解题思路:最小环长度为min{d[i][j]+d[i][k]+d[k][j]}(执行此步时,要在更新d[i][j]前)
附上代码:
//poj 3660 cow contest
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#define inf 100000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int n,m,ans=0;
bool d[110][110];
void floyd(int n)
{
rep(k,1,n)
rep(i,1,n)
rep(j,1,n)
d[i][j]|=d[i][k]&d[k][j];
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,m)
{
int u,v;
scanf("%d%d",&u,&v);
d[u][v]=1;
}
floyd(n);
rep(i,1,n){
rep(j,1,n)
{
if(i==j) continue;
if((!(d[i][j]||d[j][i]))||(d[i][j]&&d[j][i])){ans++;break;}
}
}
printf("%d\n",n-ans);
return 0;
}