图论部分备忘

其他

关于Floyd

转载自EnigmaJJ

正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为$O(n^3)$

Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B。所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,我们便设置Dis(AB) = Dis(AX) + Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。

很简单吧,代码看起来可能像下面这样:

for ( int i = 0; i < 节点个数; ++i )
    for ( int j = 0; j < 节点个数; ++j )
        for ( int k = 0; k < 节点个数; ++k )
            if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )
            {
                // 找到更短路径
                Dis[i][j] = Dis[i][k] + Dis[k][j];
            }

但是这样是错的。因为A→C的路径还没确定。

模板

强联通

//lowlink(u)为u及其后代能追溯到的最早(最先被发现)祖先点v的pre(v)值,scc_cnt为SCC计数器,sccno[i]为i所在的SCC编号

int scc_cnt, dfs_clock, pre[MAXN], lowlink[MAXN], sccno[MAXN];
stack<int> st;
vector<int> G[MAXN];
 
void DFS(int from)
{
    pre[from] = lowlink[from] = ++dfs_clock;
    st.push(from);
    for (int i = 0; i < SZ(G[from]); i++)
    {
        int to = G[from][i];
        if (!pre[to])
        {
            DFS(to);
            lowlink[from] = min(lowlink[from], lowlink[to]);
        }
        else if (!sccno[to]) lowlink[from] = min(lowlink[from], pre[to]);
    }
    if (lowlink[from] == pre[from])
    {
        scc_cnt++;
        while (1)
        {
            int x = st.top(); st.pop();
            sccno[x] = scc_cnt;
            if (x == from) break;
        }
    }
}
 
void FindSCC(int n)
{
    dfs_clock = scc_cnt = 0;
    MS(sccno, 0); MS(pre, 0); MS(lowlink, 0);
    for (int i = 1; i <= n; i++)
        if (!pre[i]) DFS(i);
}

最小生成树(Kruskal)

struct POINT
{
    double x, y;
}point[MAXN];
 
int u[MAXN], v[MAXN], p[MAXN], r[MAXN], n, k;
double dis[MAXN], ans;
 
int cmp(const int i, const int j)
{
    return dis[i] < dis[j];
}
 
int Find(int x)
{
    return p[x] == x ? x : p[x] = Find(p[x]);
}
 
void Kruskal()
{
    for (int i = 0; i < k; i++)
        p[i] = i;
    for (int i = 0; i < k; i++)
        r[i] = i;
    sort(r, r + k, cmp);
    for (int i = 0; i < k; i++)
    {
        int e = r[i];
        int x = Find(u[e]), y = Find(v[e]);
        if (x != y)
        {
            ans += dis[e];
            p[x] = y;
        }
    }
}
 
int main()
{
    //freopen("input.txt", "r", stdin);
    int T, i, j;
    scanf("%d", &T);
    while (T--)
    {
        k = ans = 0;
        scanf("%d", &n);
        for (i = 0; i < n; i++)
            scanf("%lf%lf", &point[i].x, &point[i].y);
        for (i = 0; i < n; i++)
            for (j = i + 1; j < n; j++)
            {
                u[k] = i, v[k] = j;
                dis[k++] = hypot(point[i].x - point[j].x, point[i].y - point[j].y);
            }
        Kruskal();
        printf("%.2f\n", ans);
        if (T)
            printf("\n");
    }
    return 0;
}

Floyd

void Floyd()
{
    for (int k = 1; k < MAXN; k++)
        for (int i = 1; i < MAXN; i++)
            for (int j = 1; j < MAXN; j++)
                dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]);
}

SPFA & Dijkstra

struct EDGE
{
    int from, to, cost;
};
 
struct HEAPNODE
{
    int d, u;
    bool operator < (const HEAPNODE &a) const
    {
        return d > a.d;
    }
};
 
struct S_PATH
{
    int N, cnt, d[MAXN];
    int vis[MAXN], next[MAXN * MAXN], head[MAXN];
    vector<EDGE> edges;
 
    void add_edge(int from, int to, int cost)
    {
        edges.push_back((EDGE){from, to, cost});
        int m = SZ(edges);
        next[m - 1] = head[from];
        head[from] = m - 1;
    }
 
    void init(int N)
    {
        this->N = N;
        MS(head, -1);
        edges.clear();
        cnt = 0;
    }
 
    void dijkstra(int st)
    {
        priority_queue<HEAPNODE> pqu;
        fill(d, d + N + 1, INF);
        d[st] = 0;
        pqu.push((HEAPNODE){d[st], st});
        while (!pqu.empty())
        {
            HEAPNODE x = pqu.top(); pqu.pop();
            int u = x.u;
            if (x.d != d[u]) continue;
            for (int i = head[u]; i != -1; i = next[i])
            {
                EDGE &e = edges[i];
                if (d[e.to] > d[u] + e.cost)
                {
                    d[e.to] = d[u] + e.cost;
                    pqu.push((HEAPNODE){d[e.to], e.to});
                }
            }
        }
    }
 
    void SPFA(int st)
    {
        MS(vis, 0);
        queue<int> qu;
        fill(d, d + N + 1, INF);
        d[st] = 0;
        qu.push(st);
        while (!qu.empty())
        {
            int u = qu.front(); qu.pop();
            vis[u] = 0;
            for (int i = head[u]; i != -1; i = next[i])
            {
                EDGE &e = edges[i];
                if (d[e.to] > d[u] + e.cost)
                {
                    d[e.to] = d[u] + e.cost;
                    if (!vis[e.to])
                    {
                        vis[e.to] = 1;
                        qu.push(e.to);
                    }
                }
            }
        }
    }
}s;

最小费用最大流

struct EDGE
{
    int from, to, cap, flow, cost;
};
 
struct MCMF
{
    int n, m, st, ed;
    vector<EDGE> edges;
    vector<int> G[MAXN];
    int inq[MAXN];  //是否在队列中
    int d[MAXN];    //bellman-Ford
    int p[MAXN];    //上一条弧
    int a[MAXN];    //可改进量
 
    void init(int n)
    {
        this->n = n;
        for (int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }
 
    void add_edge(int from, int to, int cap, int cost)
    {
        edges.PB((EDGE){from, to, cap, 0, cost});
        edges.PB((EDGE){to, from, 0, 0, -cost});
        m = SZ(edges);
        G[from].PB(m - 2);
        G[to].PB(m - 1);
    }
 
    bool SPFA(int st, int ed, int &flow, int &cost)
    {
        fill(d, d + n + 1, INF);
        MS(inq, 0);
        d[st] = 0; inq[st] = 1; p[st] = -1; a[st] = INF;
        queue<int> qu;
        qu.push(st);
        while (!qu.empty())
        {
            int u = qu.front(); qu.pop();
            inq[u] = 0;
            for (int i = 0; i < SZ(G[u]); i++)
            {
                EDGE &e = edges[G[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost)
                {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if (!inq[e.to])
                        qu.push(e.to), inq[e.to] = 1;
                }
            }
        }
        if (d[ed] == INF) return false;
        flow += a[ed]; cost += d[ed] * a[ed];
        int u = ed;
        while (u != st)
        {
            edges[p[u]].flow += a[ed];
            edges[p[u] ^ 1].flow -= a[ed];
            u = edges[p[u]].from;
        }
        return true;
    }
};

最大流(STL版Dinic)

struct DINIC
{
    int d[MAXN], cur[MAXN], vis[MAXN], st, ed;
    vector<EDGE> edges;
    vector<int> G[MAXN];
    void add_edge(int from, int to, int cap)
    {
        edges.PB((EDGE){from, to, cap, 0});
        edges.PB((EDGE){to, from, 0, 0});
        int m = SZ(edges);
        G[from].PB(m - 2); G[to].PB(m - 1);
    }
 
    void init(int st, int ed)
    {
        this->st = st, this->ed = ed;
        edges.clear();
        for(int i = 0; i <= ed; i++) G[i].clear();
    }
 
    int maxFlow()
    {
        int flow = 0;
        while (BFS())
        {
            MS(cur, 0);
            flow += DFS(st, INF);
        }
        return flow;
    }
  
    bool BFS()
    {
        MS(vis, 0);
        queue<int> qu;
        qu.push(st);
        d[st] = 0; vis[st] = 1;
        while (!qu.empty())
        {
            int x = qu.front(); qu.pop();
            for (int i = 0; i < SZ(G[x]); i++)
            {
                EDGE &e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    qu.push(e.to);
                }
            }
        }
        return vis[ed];
    }
 
    int DFS(int x, int a)
    {
        if (x == ed || a == 0) return a;
        int flow = 0, f;
        for (int &i = cur[x]; i < SZ(G[x]); i++)
        {
            EDGE &e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }
}maxFlow;

最大流(数组版ISAP)

struct MAXFLOW
{
    //p是前驱,num是和ed的最短距离等于i的结点数量,d是残量网络中i到ed的最短距离
    int p[MAXN], num[MAXN], cur[MAXN], d[MAXN], head[MAXN], next[MAXN * MAXN], st, ed, N;
    bool vis[MAXN];
    vector<EDGE> edges;
 
    void init(int st, int ed, int N)    //N是V的数量
    {
        this->ed = ed; this->st = st;
        this->N = N;
        edges.clear();
        MS(head, -1);
    }
 
    void add_edge(int from, int to, int cap)
    {
        edges.PB((EDGE){from, to, cap, 0});
        edges.PB((EDGE){to, from, 0, 0});
        int m = SZ(edges);
        next[m - 2] = head[from];
        head[from] = m - 2;
        next[m - 1] = head[to];
        head[to] = m - 1;
    }
 
    // 预处理, 反向 BFS 构造 d 数组
    void bfs()
    {
        memset(vis, 0, sizeof(vis));
        queue<int> qu;
        qu.push(ed);
        vis[ed] = 1; d[ed] = 0;
        while (!qu.empty())
        {
            int u = qu.front();
            qu.pop();
            for (int i = head[u]; i != -1; i = next[i])
            {
                EDGE &e = edges[i];
                if (!vis[e.to])
                {
                    vis[e.to] = true;
                    d[e.to] = d[u] + 1;
                    qu.push(e.to);
                }
            }
        }
    }
 
    // 增广
    int augment()
    {
        int u = ed, a = INF;
        // 从汇点到源点通过 p 追踪增广路径, df 为一路上最小的残量
        while (u != st)
        {
            EDGE &e = edges[p[u]];
            a = min(a, e.cap - e.flow);
            u = edges[p[u]].from;
        }
        u = ed;
        // 从汇点到源点更新流量
        while (u != st)
        {
            edges[p[u]].flow += a;
            edges[p[u]^1].flow -= a;
            u = edges[p[u]].from;
        }
        return a;
    }
 
    int max_flow()
    {
        int flow = 0;
        bfs();
        memset(num, 0, sizeof(num));
        for (int i = 0; i < N; i++) num[d[i]]++;
        int u = st;
        memset(cur, 0, sizeof(cur));
        memcpy(cur, head, sizeof head);
        while (d[st] < N)
        {
            if (u == ed)
            {
                flow += augment();
                u = st;
            }
            int ok = 0;
            for (int &i = cur[u]; i != -1; i = next[i])
            {
                EDGE& e = edges[i];
                if (e.cap > e.flow && d[u] == d[e.to] + 1)
                {
                    ok = 1;
                    p[e.to] = i;
                    u = e.to;
                    break;
                }
            }
            if (!ok)
            {
                // retreat
                int m = N - 1;
                for (int i = head[u]; i != -1; i = next[i])
                    if (edges[i].cap > edges[i].flow)
                        m = min(m, d[edges[i].to]);
                if (--num[d[u]] == 0) break; // gap 优化
                num[d[u] = m + 1]++;
                cur[u] = head[u];
                if (u != st)
                    u = edges[p[u]].from;
            }
        }
        return flow;
    }
}maxFlow;

二分图匹配匈牙利算法

struct EDGE
{
    int from, to;
};
 
struct BIMATCHING
{
    int link[MAXN], head[MAXN], next[MAXN * MAXN];
    bool vis[MAXN];
    vector<EDGE> edges;

    void init()
    {
        MS(link, -1); MS(head, -1);
        edges.clear();
    }

    void add_edge(int from, int to)
    {
        edges.PB((EDGE){from, to});
        int m = SZ(edges);
        next[m - 1] = head[from];
        head[from] = m - 1;
    }
 
    bool dfs(int u)
    {
        for (int i = head[u]; i != -1; i = next[i])
        {
            EDGE &e = edges[i];
            int v = e.to;
            if (!vis[v])
            {
                vis[v] = 1;
                if (link[v] == -1 || dfs(link[v]))
                {
                    link[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
 
    int hungary(int n)  //n是待匹配的总数,这里默认从1开始
    {
        int res = 0;
        for (int i = 1; i <= n; i++)
        {
            MS(vis, 0);
            if (dfs(i)) res++;
        }
        return res;
    }
}hun;

Powered by Jekyll and Theme by solid