【MOBAN】floyd环问题
考前狂背模板的sb玩家。
无向图最小环
dis[k][i][j]表示只经过1-->k之间的点作为路径中间点,从i到j之间的最短路径 那么最小环一定存在一个i,j,k三个相邻的点,然后i,j的编号比k小,这样保证i到j的所有路径一定不经过k,并且一定是在这种情况下刷新出的最小值void floyd() { int ans = 0x3f3f3f3f; for(int k=1;k<=n;k++) { for(int i=1;i<k;i++) { for(int j=i+1;j<k;j++) { ans = min(ans,dis[0][i][k]+dis[0][k][j]+dis[k-1][i][j]); } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { dis[k][i][j] = min(dis[k][i][j],dis[]) } } } }上面代码只针对无向图,因为想想我们上面的j=i+1就是利用了无向图的对称的优秀性质。
有向图求最小环
有向图求最小环还不简单吗?又不需要考虑路径走重边(无向图要这样诡异地枚举就是怕走到相同的边),直接两两枚举一下ans = min: ans , dis[i][j] + dis[j][i]。下面是vijos1423的code,#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; int n,m; int dis[205][205]; int w[205]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } int ans = 0x3f3f3f3f; memset(dis,0x3f,sizeof dis); for(int i=1;i<=n;i++) dis[i][i] = 0; for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); dis[x][y] = min(dis[x][y],z+w[y]); } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]); } } } for(int i=2;i<=n;i++) ans = min(ans,dis[1][i]+dis[i][1]); printf("%d",ans==0x3f3f3f3f?-1:ans); }
floyd看正负环
关于是否存在负环或正环,因为有些时候要用到floyd,同时又再写一个SPFA判负环显然是浪费代码量,这种时候其实我们只需要判断一下dis[i][i]是否<0或者>0就可以了。floyd求出包含点(边)数最小的负(正)环
我们考虑将floyd当做矩阵那么来用(也并不考虑自己刷新自己)。我们对于原图自己向自己跑多少次自矩阵,即在经过多少个点(可能的话)下的两两图的最小距离,然后预处理出一个倍增矩阵数组,然后我们找出最后一个不含负环的时刻就可以了。 bzoj4773code#include<iostream> #include<algorithm> #include<cmath> #include<cstdio> using namespace std; int n,m; struct node { int dis[305][305]; }z[10],f,owo,csh; void pao(node &a,node b,node c) { owo = csh; for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { owo.dis[i][j] = min(owo.dis[i][j],b.dis[i][k]+c.dis[k][j]); } } } a = owo; } bool pd(node &a) { for(int i=1;i<=n;i++) if(a.dis[i][i]<0) return 0; return 1; } void ts(node a) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cout<<a.dis[i][j]<<' '; } cout<<endl; } } int ss; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) csh.dis[i][j] = 0x3f3f3f3f; csh.dis[i][i] = 0; } z[0] = csh; for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); z[0].dis[u][v] = min(z[0].dis[u][v],w); } ss = ceil(log2(n)); for(int p=1;p<=ss;p++) { // ts(z[p-1]); pao(z[p],z[p-1],z[p-1]); if(!pd(z[p])){ ss = p-1; break; } } //ts(z[1]); int ans=0; node now = csh,znow; for(int p=ss;p>=0;p--) { pao(znow,now,z[p]); if(pd(znow)) { ans += (1<<p); now = znow; } } // ts(z[1]); if(ss==ceil(log2(n))&&(pd(z[ss]))) printf("0"); else printf("%d",ans+1); }