【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);
}
 
posted @ 2018-11-07 14:08  Newuser233  阅读(5)  评论(0)    收藏  举报