bzoj4773 负环 倍增+矩阵

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4773

题解

最小的负环的长度,等价于最小的 \(len\) 使得存在一条从点 \(i\) 到自己存在一条长度 \(\leq len\) 的负权路径。

为了把 \(\leq len\) 转化为 \(=len\),我们可以给每一个点建立有个边权为 \(0\) 的自环。

所以考虑倍增邻接矩阵,维护两点之间的经过 \(2^i\) 条边的最短路。

倍增的时候判断走了那么多步有没有负环就可以了。

最后结束的时候再判断一次,防止无解。



时间复杂度 \(O(n^3\log n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

const int N = 300 + 7;
const int INF = 0x3f3f3f3f;

int n, m;

struct Matrix {
    int a[N][N];

    inline Matrix() { memset(a, 0x3f, sizeof(a)); }
    inline Matrix(const int &x) {
        memset(a, 0x3f, sizeof(a));
        for (int i = 1; i <= n; ++i) a[i][i] = x;
    }

    inline Matrix operator * (const Matrix &b) {
        Matrix c;
        for (int k = 1; k <= n; ++k)
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= n; ++j)
                    smin(c.a[i][j], a[i][k] + b.a[k][j]);
        return c;
    }
} A, B[9];

inline void work() {
    B[0] = A, A = Matrix(0);
    for (int i = 1; i < 9; ++i) B[i] = B[i - 1] * B[i - 1];
    int ans = 0;
    for (int i = 8; ~i; --i) {
        Matrix C = A * B[i];
        int mn = INF;
        for (int j = 1; j <= n; ++j) smin(mn, C.a[j][j]);
        if (mn >= 0) A = C, ans += 1 << i;
    }
    A = A * B[0];
    int mn = INF;
    for (int j = 1; j <= n; ++j) smin(mn, A.a[j][j]);
    if (mn >= 0) puts("0");
    else printf("%d\n", ans + 1);
}

inline void init() {
    read(n), read(m);
    int x, y, z;
    A = Matrix(0);
    for (int i = 1; i <= m; ++i) read(x), read(y), read(z), A.a[x][y] = z;
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/hankeke/p/bzoj4773.html

时间: 2024-11-13 08:19:08

bzoj4773 负环 倍增+矩阵的相关文章

【BZOJ4773】负环 倍增Floyd

[BZOJ4773]负环 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 <

BZOJ4773: 负环

倍增floyd裸题,倍增判断走2^i步是否存在负环就好了. 其实和3763是一样的,然而那题数据挂了. #include<cstdio> void upd1(int&a,int b){ if(a>b)a=b; } const int N=301; typedef int arr[N][N]; int n; void pre(arr a){ for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=1e9; } void d

BZOJ_4773_负环_倍增弗洛伊德

BZOJ_4773_负环 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 <

负环 BZOJ 4773

负环 [问题描述] 在忘记考虑负环之后,黎瑟的算法又出错了.对于边带权的有向图 G = (V, E),请找出一个点数最小的环,使得环上的边权和为负数.保证图中不包含重边和自环. [输入格式] 第1两个整数n, m,表示图的点数和边数. 接下来的m行,每<=三个整数ui, vi, wi,表<=有一条从ui到vi,权值为wi的有向边. [输出格式] 仅一行一个整数,表示点数最小的环上的点数,若图中不存在负环输出0. [样例输入] 3 6 1 2 -2 2 1 1 2 3 -10 3 2 10 3

poj 3259 Wormholes[ bellman_ford 判负环]

Wormholes Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wor

poj 3259 Wormholes(bellman-ford判断负环)

题目链接:http://poj.org/problem?id=3259 题目就是问你能否回到原点而且时间还倒回去了.题目中有些路中有单向的虫洞能让时间回到过去 所以只要将虫洞这条边的权值赋为负然后再判断有没有负环就行了. #include <iostream> #include <cstring> using namespace std; const int inf = 10001; int f , n , m , w ,dis[1001] , counts; struct TnT

(简单) LightOJ 1074 Extended Traffic,SPFA+负环。

Description Dhaka city is getting crowded and noisy day by day. Certain roads always remain blocked in congestion. In order to convince people avoid shortest routes, and hence the crowded roads, to reach destination, the city authority has made a new

POJ 3259 虫洞旅行 spfa判负环

Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 31425   Accepted: 11431 Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way p

洛谷P3385 【模板】负环 DFS-SPFA 判负环 图论

洛谷P3385 [模板]负环 图论 今天get了 一个 DFS-SPFA 判负环的方法 一般的 BFS-SPFA 判负环 一般就是 不停地做,如果某点第 n+1次加入队列中,那么说明这个图存在负环然而我并不会证明,期望复杂度是 O(kM) k 大约是在 2 左右 但是其实对于一些极限数据,最坏可以把他卡到 O( NM) 额,这就直接炸飞了是不是,而且据说,一些数据比较强的题目,总会想到卡一卡SPFA的, 然后我们换一种思路 因为题目中一定存在一种 负环对吧,所以说假如你某段路径权值和为自然数的时