ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

在忘记考虑负环之后,黎瑟的算法又出错了。对于边带权的有向图 G = (V, E),请找出一个点数最小的环,使得
环上的边权和为负数。保证图中不包含重边和自环。

Input

第1两个整数n, m,表示图的点数和边数。
接下来的m行,每<=三个整数ui, vi, wi,表<=有一条从ui到vi,权值为wi的有向边。
2 <= n <= 300
0 <= m <= n(n <= 1)
1 <= ui, vi <= n
|wi| <= 10^4

Output

仅一行一个整数,表示点数最小的环上的点数,若图中不存在负环输出0。

对每个点加入边权0的自环后,答案变得满足二分性质,于是可以用倍增floyd处理出两两点间走2^k步的最短路,并二分出最大的不存在负环的步数,从而得出答案

时间复杂度O(n3logn)

#include<bits/stdc++.h>
const int inf=0x3f3f3f3f;
int n,m;
int f[9][307][307],g[307][307],h[307][307];
void mins(int&a,int b){if(a>b)a=b;}
int main(){
    scanf("%d%d",&n,&m);
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;++i)f[0][i][i]=0;
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        mins(f[0][a][b],c);
    }
    for(int i=0;i<8;++i){
        for(int a=1;a<=n;++a)
        for(int c=1;c<=n;++c)
        for(int b=1,x=f[i][a][c],*y=f[i][c],*z=f[i+1][a];b<=n;++b)
        mins(z[b],x+y[b]);
    }
    bool is=0;
    for(int a=1;a<=n;++a)if(f[8][a][a]<0)is=1;
    if(!is)return puts("0"),0;
    int ans=0;
    memset(g,0x3f,sizeof(g));
    for(int a=1;a<=n;++a)g[a][a]=0;
    for(int i=8;i>=0;--i){
        memset(h,0x3f,sizeof(h));
        for(int a=1;a<=n;++a)
        for(int c=1;c<=n;++c)
        for(int b=1,x=f[i][a][c],*y=g[c],*z=h[a];b<=n;++b)
        mins(z[b],x+y[b]);
        is=0;
        for(int a=1;a<=n;++a)if(h[a][a]<0)is=1;
        if(!is){
            ans|=1<<i;
            memcpy(g,h,sizeof(g));
        }
    }
    printf("%d",ans+1);
    return 0;
}

 

posted on 2017-03-18 15:54  nul  阅读(179)  评论(0编辑  收藏