关于最短路、负环、差分约束系统的一点笔记

关于最短路、负环、差分约束系统的一点笔记

最短路

“可以”没有环,最多\(|V|-1\)条边

有负环则不存在最短路

会形成最短路径树

算法

  1. Dijkstra 贪心,当\(d_u\)是最小时要满足之后\(d_u\)不会更小,不能处理负权边
  2. Bellman-Ford 迭代n-1轮,用边松弛
  3. spfa 队列优化的Bellman-Ford

最短路的线性规划形式

最大化 \(d_i\)

满足

  1. 三角不等式 \(d_v \le d_u + w(u,v),\\)
  2. \(d_s=0\)

说明:上述约束对应了无穷组解。最短路求的是满足约束的最大值。因为三角不等式要求取等号时w(u,v)是最短路上的边。

应用

差分约束系统

非DAG上DP

一般使用spfa或者缩点后dp

应为dijkstra有贪心策略的限制

负环

将所有点入队,且\(d_i=0\)

负环只看不等约束,不看初始值

算法

  1. Bellman-Ford 常数小
  2. spfa 判断 1. 入队次数>=n 2.最短路长度>=n
  3. spfa-dfs 没多大意思,轻松被卡

应用

01分数规划

代码

见最后

差分约束系统

和最短路的线性规划形式类似的一类线性规划问题

也是需要初值的,对应d[s]=0

最短路

最大化

有负环则无解

图不连通 无关 任意解

最长路

最小化

有正环则无解

图不连通 无关 任意解

当然也可以转化成最短路


附录:

判负环的代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 2005, M = 3005;

inline int read() {
    int x = 0, f = 1; char c = getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x * f;
}

int n, m;
struct edge {int v, ne, w, u;} e[M<<1];
int cnt, h[N];
inline void ins(int u, int v, int w) {
    e[++cnt] = (edge) {v, h[u], w, u}; h[u] = cnt;
}

int d[N], cou[N];
bool bellman_ford() {
    for(int i=1; i<=n; i++) d[i] = cou[i] = 0;
    for(int i=1; i<=n; i++) {
        for(int i=1; i<=cnt; i++) {
            int u = e[i].u, v = e[i].v; //printf("hi %d %d  %d %d\n", u, v, d[u], d[v]);
            if(d[v] > d[u] + e[i].w) {
                d[v] = d[u] + e[i].w;
                cou[v] = cou[u] + 1;
                if(cou[v] >= n) return false;
                if(i == n) return false;
            }
        }
    }
    return true;
}
int main() {
    freopen("in", "r", stdin);
    int T = read();
    while(T--) {
        cnt = 0; memset(h, 0, sizeof(h));

        n = read(); m = read();
        for(int i=1; i<=m; i++) {
            int u = read(), v = read(), w = read();
            if(w < 0) ins(u, v, w);
            else ins(u, v, w), ins(v, u, w);
        }
        puts(bellman_ford() ? "N0" : "YE5");
    }
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 2005, M = 3005;

inline int read() {
    int x = 0, f = 1; char c = getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x * f;
}

int n, m;
struct edge {int v, ne, w;} e[M<<1];
int cnt, h[N];
inline void ins(int u, int v, int w) {
    e[++cnt] = (edge) {v, h[u], w}; h[u] = cnt;
}
int d[N], cou[N], inq[N], cinq[N];
int q[N], head, tail;
inline void lop(int &x) {if(x==N) x=1;}
bool spfa() {
    head = tail = 1;
    for(int i=1; i<=n; i++) d[i] = cou[i] = 0, inq[i] = cinq[i] = 1, q[tail++] = i;
    while(head != tail) {
        int u = q[head++]; lop(head); inq[u] = 0;
        for(int i=h[u]; i; i=e[i].ne) {
            int v = e[i].v;
            if(d[v] > d[u] + e[i].w) {
                d[v] = d[u] + e[i].w;
                cou[v] = cou[u] + 1;
                if(cou[v] >= n) return false;
                if(!inq[v]) {
                    q[tail++] = v; lop(tail); inq[v] = 1; 
                    if(++cinq[v] >= n) return false; 
                }
            }
        }
    }
    return true;
}

int main() {
    freopen("in", "r", stdin);
    int T = read();
    while(T--) {
        cnt = 0; memset(h, 0, sizeof(h));

        n = read(); m = read();
        for(int i=1; i<=m; i++) {
            int u = read(), v = read(), w = read();
            if(w < 0) ins(u, v, w);
            else ins(u, v, w), ins(v, u, w);
        }
        puts(spfa() ? "N0" : "YE5");
    }
}
posted @ 2018-07-09 08:56 Candy? 阅读(...) 评论(...) 编辑 收藏