图论模板汇总

  1. Dijkstra算法

P4779 【模板】单源最短路径(标准版)


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<LL ,int>
const LL N = 1e5 + 10;
struct edge {
    int u, v;
    LL w;
    edge(int u, int v, LL w) :u(u), v(v), w(w){}
};
vector<vector<edge> > e(N);
int n, m, s, visit[N]; 
LL dis[N];
void dijk() {
    priority_queue<P, vector<P>, greater<P> > q;
    dis[s] = 0;
    q.push(P(dis[s], s));
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (visit[u]) continue;
        visit[u] = 1;
        for (auto i : e[u]) {
            if (dis[i.v] > dis[u] + i.w) {
                dis[i.v] = dis[u] + i.w;
                q.push(P(dis[i.v], i.v));
            }
        }
    }
}
void solve() {
    cin >> n >> m >> s;
    for (int i = 0; i < m; ++i) {
        int u, v;
        LL w;
        cin >> u >> v >> w;
        e[u].push_back(edge(u, v, w));
    }
    memset(dis, 0x3f, sizeof(dis));
    dijk();
    for (int i = 1; i <= n; ++i) {
        cout << dis[i] << " ";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. SPFA算法

P3385 【模板】负环


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<LL ,int>
const LL N = 1e5 + 10;
struct edge {
    int u, v;
    LL w;
    edge(int u, int v, LL w) :u(u), v(v), w(w) {}
};
int n, m;
int inq[N], cnt[N];
LL dis[N];
vector<vector<edge> > e(N);
int spfa(int u) {
    memset(dis, 0x3f, sizeof(dis));
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    queue<int> q;
    q.push(u);
    inq[u] = 1; 
    cnt[u] = 1;
    dis[u] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (auto i : e[u]) {
            if (dis[i.v] > dis[u] + i.w) {
                dis[i.v] = dis[u] + i.w;
                cnt[i.v]++;
                if (cnt[i.v] >= n) return 1;
                if (!inq[i.v]) {
                    q.push(i.v);
                    inq[i.v] = 1;
                }
            }
        }
    }
    return 0;
}
void solve() {
    cin >> n >> m;
    e.clear();
    e.resize(N);
    for (int i = 0; i < m; ++i) {
        int u, v;
        LL w;
        cin >> u >> v >> w;
        if (w >= 0) e[v].push_back(edge(v, u, w));
        e[u].push_back(edge(u, v, w));
    }
    if (spfa(1)) cout << "YES\n";
    else cout << "NO\n";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    //_t = 1;
    cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
//优化:deque,平均值
  1. Floyd算法


void floyd(){
    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]);
            }
        }
    }
}
  1. Johnson算法

P5905 【模板】Johnson 全源最短路


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 3e3 + 10;
struct edge {
    int u, v, w;
};
vector<vector<edge> >e(N);
int n, m;
int inq[N], dis[N], dist[N][N], vis[N], cnt[N];
bool spfa() {
    queue<int> q;
    q.push(0);
    dis[0] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (auto i : e[u]) {
            if (dis[u] + i.w < dis[i.v]) {
                dis[i.v] = dis[u] + i.w;
                cnt[i.v]++;
                if (cnt[i.v] > n) return 0;
                if (!inq[i.v]) {
                    inq[i.v] = 1;
                    q.push(i.v);
                }
            }
        }
    }
    return 1;
}
void dijk(int x) {
    priority_queue<P, vector<P>, greater<P> > q;
    dist[x][x] = 0;
    q.push({ dist[x][x],x });
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto i : e[u]) {
            if (dist[x][u] + i.w < dist[x][i.v]) {
                dist[x][i.v] = dist[x][u] + i.w;
                q.push({ dist[x][i.v],i.v });
            }
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back({ u,v,w });
    }
    for (int i = 1; i <= n; ++i) e[0].push_back({ 0,i,0 });
    memset(dis, 0x3f, sizeof(dis));
    if (!spfa()) {
        cout << -1;
        return;
    }
    for (int i = 1; i <= n; ++i) {
        for (auto& j : e[i]) {
            j.w += dis[i] - dis[j.v];
        }
    }
    memset(dist, 0x3f, sizeof(dist));
    for (int i = 1; i <= n; ++i) {
        memset(vis, 0, sizeof(vis));
        dijk(i);
    }
    for (int i = 1; i <= n; ++i) {
        ll ans = 0;
        for (int j = 1; j <= n; ++j) {
            if (dist[i][j] == 0x3f3f3f3f) dist[i][j] = 1e9;
            else dist[i][j] -= dis[i] - dis[j];
            ans += 1ll * j * dist[i][j];
        }
        cout << ans << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 多层图Dijkstra

P4568 [JLOI2011] 飞行路线


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const LL N = 11e4 + 10;
int n, m,k,st,en;
int vis[N], dis[N];
struct edge {
    int u, v, w;
    edge(int u, int v, int w) :u(u), v(v), w(w) {}
};
vector<vector<edge> > e(N);
void dijk() {
    memset(dis, 0x3f, sizeof(dis));
    priority_queue<P, vector<P>, greater<P> > q;
    dis[st] = 0;
    q.push(P(dis[st], st));
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto i : e[u]) {
            if (dis[i.v] > dis[u] + i.w) {
                dis[i.v] = dis[u] + i.w;
                q.push(P(dis[i.v], i.v));
            }
        }
    }
}
void solve() {
    cin >> n >> m >> k >> st >> en;
    for (int i = 0; i < m; ++i) {
        int x, y, c;
        cin >> x >> y >> c;
        for (int j = 0; j <= k; ++j) {
            e[x + n * j].push_back(edge(x + n * j, y + n * j, c));
            e[y + n * j].push_back(edge(y + n * j, x + n * j, c));
            if (j != k) {
                e[x + n * j].push_back(edge(x + n * j, y + n * (j + 1), 0));
                e[y + n * j].push_back(edge(y + n * j, x + n * (j + 1), 0));
                e[en + n * j].push_back(edge(en + n * j, en + n * (j + 1), 0));
            }
        }
    }
    dijk();
    cout << dis[en + n * k];
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 差分约束

P5960 【模板】差分约束算法


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e3 + 10;
struct edge {
    int u, v, w;
    edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector<vector<edge> >e(N);
int dist[N],inq[N],cnt[N],n,m;
bool spfa() {
    dist[0] = 0;
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (edge i : e[u]) {
            int v = i.v, w = i.w;
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                if (!inq[v]) {
                    inq[v] = 1;
                    cnt[v]++;
                    if (cnt[v] > n) return 0;
                    q.push(v);
                }
            }
        }
    }
    return 1;
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) e[0].push_back(edge(0, i, 0));
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[v].push_back(edge(v, u, w));
    }
    memset(dist, 0x3f, sizeof(dist));
    if (!spfa()) cout << "NO";
    else {
        for (int i = 1; i <= n; ++i) cout << dist[i] << " ";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 传递闭包

N只老虎爱跳舞


#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
int dis[110][110];
int n,m;
void floyd(){
    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]);
            }
        }
    }
}
int main(){
    cin>>n>>m;
    memset(dis,0x3f,sizeof(dis));
    for(int i=0;i<m;++i){
        int a,b;
        cin>>a>>b;
        dis[a][b]=1;
    }
    floyd();
    int ans=n;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            if(i!=j&&dis[i][j]==0x3f3f3f3f&&dis[j][i]==0x3f3f3f3f){
                ans--;
                break;
            }
        }
    }
    cout<<ans;
    return 0;
}
  1. k短路径

P2901 [USACO08MAR]Cow Jogging G


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e3 + 10;
struct edge {
    int u, v, w;
    edge(int u,int v,int w):u(u),v(v),w(w){}
};
struct node {
    int id;
    LL g, h;
    node(int id,LL g,LL h):id(id),g(g),h(h){}
    bool operator<(const node a)const {
        return g + h > a.g + a.h;
    }
};
vector<vector<edge> >e(N);
vector<vector<edge> >e2(N);
int n, m, k;
LL dis[N], cnt[N],vis[N],ans[110];
void dijk(int x) {
    dis[x] = 0;
    priority_queue<P, vector<P>, greater<P> >q;
    q.push(P(dis[x], x));
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto i : e2[u]) {
            if (dis[i.v] > dis[u] + i.w) {
                dis[i.v] = dis[u] + i.w;
                q.push(P(dis[i.v],i.v));
            }
        }
    }
}
void astar(int s, int t, int k) {
    priority_queue<node> q;
    q.push(node(s, 0, dis[s]));
    while (!q.empty()) {
        node u = q.top();
        q.pop();
        cnt[u.id]++;
        if (u.id == t) {
            ans[cnt[u.id]] = u.g;
            if (cnt[u.id] == k) return;
        }
        for (auto i : e[u.id]) {
            q.push(node(i.v, u.g+i.w, dis[i.v]));
        }
    }
}
void solve() {
    cin >> n >> m >> k;
    for (int i = 1; i <= m; ++i) {
        int x, y, z;
        cin >> x >> y >> z;
        e[x].push_back(edge(x, y, z));
        e2[y].push_back(edge(y, x, z));
     }
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 1; i <= k; ++i) ans[i] = -1;
    dijk(1);
    astar(n, 1, k);
    for (int i = 1; i <= k; ++i) {
        cout << ans[i] << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. Kruskal算法

P3366 【模板】最小生成树


#include<iostream>
#include<algorithm>
using namespace std;
const LL N = 5e3 + 10;
const LL M = 2e5 + 10;
int f[N], cnt[N],n,m;
struct edge {
    int u, v, w;
    edge(int u,int v,int w):u(u),v(v),w(w){}
    edge(){}
    bool operator<(const edge a)const {
        return w < a.w;
    }
}e[M];
void init() {
    for (int i = 1; i <= n; ++i) {
        f[i] = i;
        cnt[i] = 0;
    }
}
int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
void merge(int x, int y) {
    x = find(x);
    y = find(y);
    if (cnt[x] > cnt[y]) f[y] = x;
    else {
        if (cnt[x] == cnt[y]) cnt[y]++;
        f[x] = y;
    }
}
bool query(int x, int y) {
    return find(x) == find(y);
}
int main() {
    cin >> n >> m;
    long long ans = 0;
    int cur = 0;
    init();
    for (int i = 0; i < m; ++i) {
        int x, y, z;
        cin >> x >> y >> z;
        e[i] = edge(x, y, z);
    }
    sort(e, e + m);
    for (int i = 0; i < m; ++i) {
        if (query(e[i].u, e[i].v)==0) {
            merge(e[i].u, e[i].v);
            ans += e[i].w;
            cur++;
        }
        if (cur == n - 1) break;
    }
    if (cur == n - 1) cout << ans;
    else cout << "orz";
    return 0;
}
  1. Prim算法

P3366 【模板】最小生成树


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
const LL N = 5e3 + 10;
int n, m, vis[N];
LL ans;
struct edge {
    int u, v, w;
    edge(int u, int v, int w) :u(u), v(v), w(w) {}
};
struct node {
    int id, dis;
    node(int id, int dis) :id(id), dis(dis) {}
    bool operator<(const node a)const {
        return dis > a.dis;
    }
};
vector<vector<edge> > e(N);
bool  prim() {
    int cnt = 0;
    priority_queue<node> q;
    q.push(node(1, 0));
    while (!q.empty()) {
        node u = q.top();
        q.pop();
        if (vis[u.id]) continue;
        vis[u.id] = 1;
        ans += u.dis;
        cnt++;
        for (auto i : e[u.id]) {
            if (vis[i.v]) continue;
            q.push(node(i.v, i.w));
        }
        if (cnt == n) return 1;
    }
    return 0;
}
void solve() {
    cin >> n >> m;
    ans = 0;
    for (int i = 0; i < m; ++i) {
        int x, y, z;
        cin >> x >> y >> z;
        e[x].push_back(edge(x, y, z));
        e[y].push_back(edge(y, x, z));
    }
    if (prim()) cout << ans;
    else cout << "orz";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 严格次小生成树

P4180 [BJWC2010] 严格次小生成树


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 3e5 + 10;
struct edge {
    int u, v, w;
    edge(){}
    edge(int u, int v, int w) :u(u), v(v), w(w){}
    bool operator<(const edge a)const {
        return w < a.w;
    }
}e[N];
int n, m, deep[N], f[N][20], dist1[N][20], dist2[N][20],fa[N],intree[N],d[N],cnt=0,num=0,cnta[N],cntb[N];
LL sum = 0,ans=INF;
vector<vector<edge> >p(N); 
inline int read() {
    char c = getchar(); int x = 0;
    while (c < '0' || c > '9') { c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x;
}
inline void init() {
    for (register int i = 1; i <= n; ++i) fa[i] = i;
}
inline int find(int x) {
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}
inline void merge(int a, int b) {
    a = find(a);
    b = find(b);
    if (cnta[a] < cntb[b]) fa[a] = b;
    else {
        if (cnta[a] == cntb[b]) cnta[a]++;
        fa[b] = a;
    }
}
inline bool query(int a, int b) {
    return find(a) == find(b);
}
void dfs(int x) {
    for (edge i : p[x]) {
        int v = i.v, w = i.w;
        if (v == f[x][0]) continue;
        deep[v] = deep[x] + 1;
        f[v][0] = x;
        dist1[v][0] = w;
        for (register int j = 1; (1 << j) <= deep[v]; ++j) {
            f[v][j] = f[f[v][j - 1]][j - 1];
            d[0] = dist1[v][j - 1], d[1] = dist1[f[v][j - 1]][j - 1], d[2] = dist2[v][j - 1], d[3] = dist2[f[v][j - 1]][j - 1];
            for (register int k = 0; k < 4; ++k) {
                if (d[k] > dist1[v][j]) dist2[v][j] = dist1[v][j],dist1[v][j] = d[k] ;
                else if (d[k] != dist1[v][j] && d[k] > dist2[v][j]) dist2[v][j] = d[k];
            }
        }
        dfs(v);
    }
}
int lca(int x, int y,int w) {
    if (deep[x] < deep[y]) swap(x, y);
    for (register int i = 19; i >= 0; --i) {
        if (deep[f[x][i]] >= deep[y]) {
            d[++num] = dist1[x][i];
            d[++num] = dist2[x][i];
            x = f[x][i];
        }
    }
    if (x != y) {
        for (register int i = 19; i >= 0; --i) {
            if (f[x][i] != f[y][i]) {
                d[++num] = dist1[x][i];
                d[++num] = dist1[y][i];
                d[++num] = dist2[x][i];
                d[++num] = dist2[y][i];
                x = f[x][i];
                y = f[y][i];
            }
        }
        d[++num] = dist1[x][0];
        d[++num] = dist1[y][0];
    }
    int d1 = 0, d2 = 0;
    for (register int i = 1; i <= num; ++i) {
        if (d[i] > d1) d2 = d1,d1 = d[i];
        else if (d[i] != d1 && d[i] > d2) d2 = d[i];
    }
    if (w == d1) return w - d2;
    else return w - d1;
}
void solve() {
    n=read(),m=read();
    for (register int i = 1; i <= m; ++i) {
        int u, v, w;
        u = read(), v = read(), w = read();
        e[i] = edge(u, v, w);
    }
    sort(e + 1, e + m + 1);
    init();
    for (register int i = 1; i <= m; ++i) {
        int u = e[i].u, v = e[i].v,w=e[i].w;
        if (u == v) continue;
        if (!query(u,v)) {
            merge(u, v);
            cnt++;
            sum += w;
            p[u].push_back(edge(u, v, w));
            p[v].push_back(edge(v, u, w));
            intree[i] = 1;
        }
        if (cnt == n - 1) break;
    }
    deep[1] = 1;
    dfs(1);
    for (register int i = 1; i <= m; ++i) {
        if (intree[i]) continue;
        int u = e[i].u, v = e[i].v,w=e[i].w;
        if (u == v) continue;
        num = 0;
        ans = min(ans, sum + lca(u, v, w));
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 拓扑排序


void topo() {
    queue<int> q;
    for (int i = 1; i <= n; ++i) {
        if (in[i] == 0) q.push(i);
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i : e[u]) {
            in[i]--;
            if (in[i] == 0) q.push(i);
        }
    }
}
  1. 基环树DP

P1453 城市环路


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const LL N = 1e5 + 10;
vector<vector<int> >e(N);
LL n, p[N],in[N],vis[N],dp[N][2];
double k;
void dfs(int a,int b,int x) {
    vis[x]=1;
    dp[x][0] = dp[x][1] = 0;
    for (int i : e[x]) {
        if (vis[i]||x == b && i == a) continue;
        dfs(a, b, i);
        dp[x][1] += dp[i][0];
        dp[x][0] += max(dp[i][1], dp[i][0]);
    }
    dp[x][1] += p[x];
}
void topo() {
    queue<int> q;
    for (int i = 0; i < n; ++i) {
        if (in[i] == 1) q.push(i);
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i : e[u]) {
            in[i]--;
            if (in[i] == 1) q.push(i);
        }
    }
}
void solve() {
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> p[i];
    for (int i = 0; i < n; ++i) {
        int a, b;
        cin >> a >> b;
        e[a].push_back(b);
        e[b].push_back(a);
        in[a]++;
        in[b]++;
    }
    cin >> k;
    topo();
    for (int i = 0; i < n; ++i) {
        if (in[i] == 2) {
            for (int j : e[i]) {
                if (in[j] == 2) {
                    dfs(j, i, i);
                    LL ans = dp[i][0];
                    memset(vis, 0, sizeof(vis));
                    dfs(i, j, j);
                    cout << setiosflags(ios::fixed) << setprecision(1) << max(ans, dp[j][0]) * k;
                    return;
                }
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 割点

P3388 【模板】割点(割顶)


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const LL N = 2e4 + 10;
vector<vector<int> >e(N);
int n, m, num[N], low[N], cnt = 0,dfn = 0,cut[N];
void tarjan(int x,int fa) {
    num[x] = low[x] = ++dfn;
    int child = 0;
    for (int i : e[x]) {
        if (num[i] == 0) {
            child++;
            tarjan(i, x);
            low[x] = min(low[x], low[i]);
            if (num[x] <= low[i] && x != fa) cut[x] = 1;//num[x]<low[i]割边
        }
        else if (i != fa) low[x] = min(low[x], num[i]);
    }
    if (x == fa && child >= 2) cut[x] = 1;
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    for (int i = 1; i <= n; ++i) {
        if (!num[i]) tarjan(i,i);
    }
    for (int i = 1; i <= n; ++i) cnt += cut[i];
    cout << cnt << '\n';
    for (int i = 1; i <= n; ++i) {
        if (cut[i]) cout << i << " ";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 点双连通分量

P8435 【模板】点双连通分量


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 5e5 + 10;
vector<vector<int> >e(N);
vector<vector<int> >vdcc(N);
int num[N], low[N], dfn, tot;
stack<int> st;
void tarjan(int x, int fa) {
    st.push(x);
    num[x] = low[x] = ++dfn;
    int child = 0;
    for (int i : e[x]) {
        if (!num[i]) {
            child++;
            tarjan(i, x);
            low[x] = min(low[x], low[i]);
            if (num[x] <= low[i]) {
                tot++;
                int u = -1;
                while (u != i) {
                    u = st.top();
                    st.pop();
                    vdcc[tot].push_back(u);
                }
                vdcc[tot].push_back(x);
            }
        }
        else if (i != fa) low[x] = min(low[x], num[i]);
    }
    if (x == fa && child == 0)  vdcc[++tot].push_back(x);
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for (int i = 1; i <= n; ++i) {
        if (!num[i]) tarjan(i, i);
    }
    cout << tot << '\n';
    for (int i = 1; i <= tot; ++i) {
        cout << vdcc[i].size() << " ";
        for (int j : vdcc[i]) cout << j << " ";
        cout << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 边双连通分量

P8436 【模板】边双连通分量


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 4e6 + 10;
vector<vector<int> >edcc(N);
int h[N], nx[N], to[N], cnt = 1;
int num[N], low[N], dfn, tot;
stack<int> st;
void add(int x, int y) {
    nx[++cnt] = h[x], h[x] = cnt, to[cnt] = y;
}
void tarjan(int x, int edge) {
    st.push(x);
    num[x] = low[x] = ++dfn;
    for (int i = h[x]; i; i = nx[i]) {
        int v = to[i];
        if (!num[v]) {
            tarjan(v, i);
            low[x] = min(low[x], low[v]);
        }
        else  if ((i ^ 1) != edge) low[x] = min(low[x], num[v]);
    }
    if (num[x] == low[x]) {
        ++tot;
        int u = -1;
        while (u != x) {
            u = st.top();
            st.pop();
            edcc[tot].push_back(u);
        }
    }
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        if (u > v) swap(u, v);
        add(u, v), add(v, u);
    }
    for (int i = 1; i <= n; ++i) {
        if (!num[i]) tarjan(i, -1);
    }
    cout << tot << '\n';
    for (int i = 1; i <= tot; ++i) {
        cout << edcc[i].size() << " ";
        for (int j : edcc[i]) cout << j << " ";
        cout << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. tarjan算法/缩点

P3387 【模板】缩点


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const LL N = 1e4 + 10;
vector<vector<int> >e(N);
vector<vector<int> >p(N);
stack<int> st;
int a[N],n,m,num[N],low[N],sccno[N],cnt=0,val[N],in[N],dp[N],vis[N],dfn=0;
void tarjan(int x) {
    st.push(x);
    num[x] = low[x] = ++dfn;
    for (int i : e[x]) {
        if (num[i] == 0) {
            tarjan(i);
            low[x] = min(low[x], low[i]);
        }
        else if (sccno[i] == 0) low[x] = min(low[x], num[i]);
    }
    if (low[x] == num[x]) {
        cnt++;
        int u = -1;
        while (u != x) {
            u = st.top();
            st.pop();
            sccno[u] = cnt;
        }
    }
}
void topo() {
    queue<int> q;
    for (int i = 1; i <= cnt; ++i) {
        if (in[i] == 0)q.push(i);
        dp[i] = val[i];
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i : p[u]) {
            dp[i] = max(dp[i], dp[u] + val[i]);
            in[i]--;
            if (in[i] == 0) q.push(i);
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 1; i <= m; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
    }
    for (int i = 1; i <= n; ++i) {
        if (num[i] == 0) tarjan(i);
    }
    for (int i = 1; i <= n; ++i) {
        for (int j : e[i]) {
            if (sccno[i] != sccno[j]) {
                p[sccno[i]].push_back(sccno[j]);
                in[sccno[j]]++;
            }
        }
    }
    topo();
    int ans = 0;
    for (int i = 1; i <= cnt; ++i) {
        ans = max(ans, dp[i]);
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 2-SAT问题

P4782 【模板】2-SAT 问题


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const int N = 2e6 + 10;
vector<vector<int> >e(N);
int n, m, num[N], low[N], sscno[N], dfn = 0, cnt = 0;
stack<int> st;
void tarjan(int x) {
    st.push(x);
    num[x] = low[x] = dfn++;
    for (int i : e[x]) {
        if (!num[i]) {
            tarjan(i);
            low[x] = min(low[x], low[i]);
        }
        else if (!sscno[i]) {
            low[x] = min(low[x], num[i]);
        }
    }
    if (low[x] == num[x]) {
        ++cnt;
        int u = -1;
        while (u != x) {
            u = st.top();
            st.pop();
            sscno[u] = cnt;
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        e[a + (1 - b) * n].push_back(c + d * n);
        e[c + (1 - d) * n].push_back(a + b * n);
    }
    for (int i = 1; i <= 2 * n; ++i) {
        if (!num[i])tarjan(i);
    }
    for (int i = 1; i <= n; ++i) {
        if (sscno[i] == sscno[i + n]) {
            cout << "IMPOSSIBLE";
            return;
        }
    }
    cout << "POSSIBLE\n";
    for (int i = 1; i <= n; ++i) {
        cout << (sscno[i] > sscno[i + n]) << " ";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. EK算法

P3376 【模板】网络最大流


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
    int u, v, n;
    LL f;
    edge() {}
    edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
LL  flow[N];
int n, m, s, t, cnt = 1, head[N], pre[N];
void add(int u, int v, LL f) {
    cnt++;
    e[cnt] = edge(u, v, f, head[u]);
    head[u] = cnt;
}
bool bfs() {
    memset(pre, 0, sizeof(pre));
    flow[s] = INF;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        if (u == t) return 1;
        for (int i = head[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i].f;
            if (f > 0 && !pre[v]) {
                flow[v] = min(flow[u], f);
                pre[v] = i;
                q.push(v);
            }
        }
    }
    return 0;
}
LL MaxFlow() {
    LL ans = 0;
    while (1) {
        if (!bfs()) break;
        ans += flow[t];
        int cur = t;
        while (cur != s) {
            e[pre[cur]].f -= flow[t];
            e[pre[cur] ^ 1].f += flow[t];
            cur = e[pre[cur]].u;
        }
    }
    return ans;
}
void solve() {
    cin >> n >> m >> s >> t;
    for (int i = 1; i <= m; ++i) {
        int u, v;
        LL f;
        cin >> u >> v >> f;
        add(u, v, f);
        add(v, u, 0);
    }
    cout << MaxFlow();
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. Dinic算法

P3376 【模板】网络最大流


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
    int u, v, n;
    LL f;
    edge() {}
    edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[MAXN];
int n, m, s, t, cnt = 1, head[N],deep[N],now[N];
void add(int u, int v, LL f) {
    cnt++;
    e[cnt] = edge(u, v, f, head[u]);
    head[u] = cnt;
}
bool bfs() {
    memcpy(now, head, sizeof(head));
    deep[s] = 1;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i].f;
            if (f > 0 && !deep[v]) {
                deep[v] = deep[u] + 1;
                if (v == t) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
LL dfs(int u, LL sum) {
    if (u == t) return sum;
    LL flow = 0;
    for (int i = now[u]; i&&sum; i = e[i].n) {
        now[u] = i;
        int v = e[i].v;
        LL f = e[i].f;
        if (f > 0 && deep[v] == deep[u] + 1) {
            LL k = dfs(v, min(sum, f));
            if (k == 0) deep[v] = 0;
            e[i].f -= k;
            e[i ^ 1].f += k;
            flow += k;
            sum -= k;
        }
    }
    return flow;
}
void solve() {
    cin >> n >> m >> s >> t;
    for (int i = 1; i <= m; ++i) {
        int u, v;
        LL f;
        cin >> u >> v >> f;
        add(u, v, f);
        add(v, u, 0);
    }
    LL ans = 0;
    while (bfs()) ans += dfs(s, INF);
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. ISAP算法

P3376 【模板】网络最大流


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
    int u, v, n;
    LL f;
    edge() {}
    edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[MAXN];
int n, m, s, t, cnt = 1, head[N], pre[N],now[N],gap[N],deep[N];
void add(int u, int v, LL f) {
    cnt++;
    e[cnt] = edge(u, v, f, head[u]);
    head[u] = cnt;
}
void bfs() {
    memcpy(now, head, sizeof(head));
    deep[t] = 1;
    queue<int> q;
    q.push(t);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        gap[deep[u]]++;
        for (int i = head[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i^1].f;
            if (!deep[v] && f) {
                deep[v] = deep[u] + 1;
                q.push(v);
            }
        }
    }
}
LL augement() {
    int cur = t;
    LL flow = INF;
    while (cur != s) {
        flow = min(flow, e[pre[cur]].f);
        cur = e[pre[cur]].u;
    }
    cur = t;
    while (cur != s) {
        e[pre[cur]].f -= flow;
        e[pre[cur] ^ 1].f += flow;
        cur = e[pre[cur]].u;
    }
    return flow;
}
void isap() {
    bfs();
    LL flow = 0;
    int u = s;
    while (deep[s] <= n) {
        if (u == t) {
            flow += augement();
            u = s;
        }
        bool ok = 0;
        for (int i = now[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i].f;
            if (f && deep[v] + 1 == deep[u]) {
                ok = 1;
                now[u] = i;
                pre[v] = i;
                u = v;
                break;
            }
        }
        if (!ok) {
            if (!--gap[deep[u]]) break;
            int mindeep = n + 10;
            for (int i = head[u]; i; i = e[i].n) {
                int v = e[i].v;
                LL f = e[i].f;
                if (f) mindeep = min(mindeep, deep[v]);
            }
            deep[u] = mindeep + 1;
            gap[deep[u]]++;
            now[u] = head[u];
            if (u != s) u = e[pre[u]].u;
        }
        
    }
    cout << flow;
}
void solve() {
    cin >> n >> m >> s >> t;
    for (int i = 1; i <= m; ++i) {
        int u, v;
        LL f;
        cin >> u >> v >> f;
        add(u, v, f);
        add(v, u, 0);
    }
    isap();
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. HLPP算法

P4722 【模板】最大流 加强版 / 预流推进


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 3e5 + 10;
struct edge {
    int u, v, n;
    LL f;
    edge() {}
    edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
LL  flow[N], ex[N];
int n, m, s, t, cnt = 1, head[N], pre[N], now[N], gap[N], deep[N], inq[N];
struct cmp {
    bool operator()(const int a, const int b) const {
        return deep[a] < deep[b];
    }
};
int read() {
    int res = 0;
    char ch = getchar();
    while (ch < '0' || ch>'9') { ch = getchar(); }
    while (ch >= '0' && ch <= '9') { res = res * 10 + ch - '0'; ch = getchar(); }
    return res;
}
void add(int u, int v, LL f) {
    cnt++;
    e[cnt] = edge(u, v, f, head[u]);
    head[u] = cnt;
}
void bfs() {
    for (int i = 1; i <= n; ++i) deep[i] = n + 1;
    deep[t] = 1;
    queue<int> q;
    q.push(t);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (register int i = head[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i ^ 1].f;
            if (f && deep[v] == n + 1) {
                deep[v] = deep[u] + 1;
                q.push(v);
            }
        }
    }
}
void hlpp() {
    bfs();
    priority_queue<int, vector<int>, cmp> q;
    deep[s] = n + 1;
    for (register int i = 1; i <= n; ++i)gap[deep[i]]++;
    for (register int i = head[s]; i; i = e[i].n) {
        int v = e[i].v;
        LL f = e[i].f;
        if (f) {
            e[i].f -= f;
            e[i ^ 1].f += f;
            ex[s] -= f;
            ex[v] += f;
            if (!inq[v] && v != s && v != t) {
                inq[v] = 1;
                q.push(v);
            }
        }
    }
    while (!q.empty()) {
        int u = q.top();
        q.pop();
        inq[u] = 0;
        for (register int i = head[u]; i; i = e[i].n) {
            int v = e[i].v;
            LL f = e[i].f;
            if (f && deep[v] + 1 == deep[u]) {
                int k = min(ex[u], f);
                e[i].f -= k;
                e[i ^ 1].f += k;
                ex[u] -= k;
                ex[v] += k;
                if (!inq[v] && v != s && v != t) {
                    inq[v] = 1;
                    q.push(v);
                }
                if (!ex[u]) break;
            }
        }
        if (ex[u]) {
            if (!--gap[deep[u]]) {
                for (register int i = 1; i <= n; i++) {
                    if (i != s && i != t && deep[i] > deep[u] && deep[i] < n + 1) {
                        deep[i] = n + 1;
                    }
                }
            }
            int mindeep = 0x3f3f3f3f;
            for (register int i = head[u]; i; i = e[i].n) {
                int v = e[i].v;
                LL f = e[i].f;
                if (f) mindeep = min(mindeep, deep[v]);
            }
            deep[u] = mindeep + 1;
            gap[deep[u]]++;
            inq[u] = 1;
            q.push(u);
        }
    }
    cout << ex[t];
}
void solve() {
    n = read(), m = read(), s = read(), t = read();
    for (register int i = 1; i <= m; ++i) {
        int u, v;
        LL f;
        u = read(), v = read(), f = read();
        add(u, v, f);
        add(v, u, 0);
    }
    hlpp();
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 二分图最大匹配(匈牙利算法)

P3386 【模板】二分图最大匹配

最大流做法


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e4 + 10;
int n, m, p,sum=0,match[N],vis[N];
vector<vector<int> > e(N);
bool dfs(int x) {
    for (int i:e[x]) {
        if (!vis[i]) {
            vis[i] = 1;
            if (!match[i] || dfs(match[i])) {
                match[i] = x;
                return 1;
            }
        }
    }
    return 0;
}
void solve() {
    cin >> n >> m >> p;
    for (int i = 1; i <= p; ++i) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
    }
    for (int i = 1; i <= n; ++i) {
        memset(vis, 0, sizeof(vis));
        if (dfs(i)) sum++;
    }
    cout << sum;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 二分图最大权匹配(KM算法)

P6577 【模板】二分图最大权完美匹配


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e2 + 10;
int mx[N], my[N], pre[N], vx[N], vy[N], n, m;
LL slack[N], e[N][N], wx[N], wy[N], d;
void augement(int x) {
    while (x) {
        my[x] = pre[x];
        int t = mx[pre[x]];
        mx[pre[x]] = x;
        x = t;
    }
}
void bfs(int x) {
    queue<int> q;
    q.push(x);
    while (1) {
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            vx[u] = 1;
            for (int i = 1; i <= n; ++i) {
                if (!vy[i] && wx[u] + wy[i] - e[u][i] < slack[i]) {
                    slack[i] = wx[u] + wy[i] - e[u][i];
                    pre[i] = u;
                    if (!slack[i]) {
                        vy[i] = 1;
                        if (!my[i]) {
                            augement(i);
                            return;
                        }
                        else q.push(my[i]);
                    }
                }
            }
        }
        d = INF;
        for (int i = 1; i <= n; ++i)if (!vy[i]) d = min(d, slack[i]);
        for (int i = 1; i <= n; ++i) {
            if (vx[i]) wx[i] -= d;
            if (vy[i]) wy[i] += d;
            else slack[i] -= d;
        }
        for (int i = 1; i <= n; ++i) {
            if (!vy[i] && !slack[i]) {
                vy[i] = 1;
                if (!my[i]) {
                    augement(i);
                    return;
                }
                else q.push(my[i]);
            }
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            e[i][j] = -INF;
        }
    }
    for (int i = 1; i <= m; ++i) {
        int x, y, w;
        cin >> x >> y >> w;
        e[x][y] = w;
        wx[x] = max(wx[x], 1LL * w);
    }
    for (int i = 1; i <= n; ++i) {
        memset(vx, 0, sizeof(vx));
        memset(vy, 0, sizeof(vy));
        fill(slack + 1, slack + n + 1, INF);
        bfs(i);
    }
    LL ans = 0;
    for (int i = 1; i <= n; ++i) ans += e[i][mx[i]];
    cout << ans << '\n';
    for (int i = 1; i <= n; ++i) cout << my[i] << " ";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 一般图最大匹配

P6113 【模板】一般图最大匹配

待填

  1. 最小费用最大流

P3381 【模板】最小费用最大流


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e5 + 10;
struct edge {
    int u, v, f, c,n;
    edge(){}
    edge(int u,int v,int f,int c,int n):u(u),v(v),f(f),c(c),n(n) {}
}e[N];
int head[N],pre[N],inq[N],dist[N],flow[N], cnt =1,n,m,s,t;
void add(int u, int v, int f, int c) {
    cnt++;
    e[cnt] = edge(u, v, f, c, head[u]);
    head[u] = cnt;
}
bool spfa() {
    memset(pre, 0, sizeof(pre));
    memset(inq, 0, sizeof(inq));
    memset(dist, 0x3f, sizeof(dist));
    memset(flow, 0x3f, sizeof(flow));
    dist[s] = 0;
    inq[s] = 1;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (int i = head[u]; i; i = e[i].n) {
            int v = e[i].v, f = e[i].f, c = e[i].c;
            if (f&&dist[v] > dist[u] + c) {
                dist[v] = dist[u] + c;
                pre[v] = i;
                flow[v] = min(flow[u], f);
                if (!inq[v]) {
                    inq[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if (dist[t] == 0x3f3f3f3f) return 0;
    else return 1;
}
void maxflow() {
    LL maxflow = 0, mincost = 0;
    while (spfa()) {
        int cur = t;
        while (cur != s) {
            e[pre[cur]].f -= flow[t];
            e[pre[cur] ^ 1].f += flow[t];
            cur = e[pre[cur]].u;
        }
        maxflow += flow[t];
        mincost += 1LL*dist[t]*flow[t];
    }
    cout << maxflow << " " << mincost;
}
void solve() {
    cin >> n >> m >> s >> t;
    for (int i = 1; i <= m; ++i) {
        int u, v, f, c;
        cin >> u >> v >> f >> c;
        add(u, v, f, c);
        add(v, u, 0, -c);
    }
    maxflow();
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 有源汇上下界最大流

P5192 Zoj3229 Shoot the Bullet|东方文花帖|【模板】有源汇上下界最大流


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const int INF = 1e9;
const LL N = 1e6 + 10;
struct edge {
    int u, v, f, n;
    edge() {}
    edge(int u, int v, int f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
int n, m, s1, s2, t1, t2, cnt, head[N],deep[N],gap[N],now[N],pre[N],fl[N];
void add(int u, int v, int f) {
    cnt++;
    e[cnt] = edge(u, v, f, head[u]);
    head[u] = cnt;
}
void bfs(int s,int t) {
    memcpy(now, head, sizeof(head));
    memset(deep, 0, sizeof(deep));
    memset(gap, 0, sizeof(gap));
    deep[t] = 1;
    queue<int> q;
    q.push(t);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        gap[deep[u]]++;
        for (int i = head[u]; i; i = e[i].n) {
            int v = e[i].v, f = e[i^1].f;
            if (f && !deep[v]) {
                deep[v] = deep[u] + 1;
                q.push(v);
            }
        }
    }
}
int augement(int s,int t) {
    int flow = INF, cur = t;
    while (cur != s) {
        flow = min(flow, e[pre[cur]].f);
        cur = e[pre[cur]].u;
    }
    cur = t;
    while (cur != s) {
        e[pre[cur]].f -= flow;
        e[pre[cur] ^ 1].f += flow;
        cur = e[pre[cur]].u;
    }
    return flow;
}
LL isap(int s, int t) {
    bfs(s,t);
    LL flow = 0;
    int u = s;
    while (deep[s] <= n + m + 4) {
        if (u == t) {
            flow += augement(s,t);
            u = s;
        }
        bool ok = 0;
        for (int i = now[u]; i; i = e[i].n) {
            int v = e[i].v, f = e[i].f;
            if (f&&deep[v]+1==deep[u]) {
                now[u] = i;
                pre[v] = i;
                ok = 1;
                u = v;
                break;
            }
        }
        if (!ok) {
            if (!--gap[deep[u]]) break;
            int mindeep = n+m+10;
            for (int i = head[u]; i; i = e[i].n) {
                int v = e[i].v, f = e[i].f;
                if (f) mindeep = min(mindeep, deep[v]);
            }
            deep[u] = mindeep+1;
            gap[deep[u]]++;
            now[u] = head[u];
            if(u!=s) u = e[pre[u]].u;
        }
    }
    return flow;
}
void solve() {
    while (cin >> n >> m) {
        memset(fl, 0, sizeof(fl));
        memset(head, 0, sizeof(head));
        s1 = n + m + 1, t1 = n + m + 2, s2 = n + m + 3, t2 = n + m + 4,cnt=1;
        LL sum = 0;
        for (int i = 1; i <= m; ++i) {
            int g;
            cin >> g;
            add(n + i, t1,INF);
            add(t1, n + i,0);
            fl[n + i] -= g, fl[t1] += g;
        }
        for (int i = 1; i <= n; ++i) {
            int c, d;
            cin >> c >> d;
            add(s1, i, d);
            add(i, s1, 0);
            for (int j = 1; j <=c; ++j) {
                int t, l, r;
                cin >> t >> l >> r;
                t++;
                add(i, n + t, r-l);
                add(n + t, i, 0);
                fl[i] -= l, fl[n + t] += l;
            }
        }
        for (int i = 1; i <= n + m + 2; ++i) {
            if (fl[i] < 0) {
                add(i, t2, -fl[i]);
                add(t2, i, 0);
            }
            else {
                add(s2, i, fl[i]);
                add(i,s2,0);
                sum += fl[i];
            }
        }
        add(t1, s1,INF);
        add(s1, t1, 0);
        if (isap(s2, t2) != sum) {
            cout << -1 << "\n\n";
            continue;
        }
        e[cnt].f = e[cnt ^ 1].f = 0;
        cout << sum + isap(s1, t1) << "\n\n";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 最小树形图(朱刘算法)

P4716 【模板】最小树形图


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 1e2 + 10;
stack<int> st;
int n, m, r;
int d[N][N], bd[N][N], num[N], low[N], sccno[N], vis[N], pre[N], dfn, cnt;
void dfs(int x) {
    vis[x] = 1;
    for (int i = 1; i <= n; ++i) {
        if (d[x][i] != INF && !vis[i]) dfs(i);
    }
}
void tarjan(int x) {
    st.push(x);
    num[x] = low[x] = ++dfn;
    if (num[pre[x]] == 0) {
        tarjan(pre[x]);
        low[x] = min(low[x], low[pre[x]]);
    }
    else if (sccno[pre[x]] == 0) low[x] = min(low[x], num[pre[x]]);
    if (low[x] == num[x]) {
        cnt++;
        int u = -1;
        while (u != x) {
            u = st.top();
            st.pop();
            sccno[u] = cnt;
        }
    }
}
void solve() {
    cin >> n >> m >> r;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) d[i][j] = INF;
    }
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        if (u != v && v != r) d[u][v] = min(d[u][v], w);
    }
    dfs(r);
    for (int i = 1; i <= n; ++i) {
        if (!vis[i]) {
            cout << -1;
            return;
        }
    }
    ll res = 0;
    while (1) {
        for (int i = 1; i <= n; ++i) {
            pre[i] = i;
            for (int j = 1; j <= n; ++j) {
                if (d[j][i] < d[pre[i]][i]) pre[i] = j;
            }
        }
        memset(num, 0, sizeof(num));
        memset(sccno, 0, sizeof(sccno));
        dfn = cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (!num[i]) tarjan(i);
        }
        if (cnt == n) {
            for (int i = 1; i <= n; ++i) {
                if (i == r) continue;
                res += d[pre[i]][i];
            }
            break;
        }
        else {
            for (int i = 1; i <= n; ++i) {
                if (i == r) continue;
                if (sccno[i] == sccno[pre[i]]) res += d[pre[i]][i];
            }
            for (int i = 1; i <= cnt; ++i) {
                for (int j = 1; j <= cnt; ++j) bd[i][j] = INF;
            }
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= n; ++j) {
                    if (d[i][j] != INF && sccno[i] != sccno[j]) {
                        if (sccno[pre[j]] == sccno[j]) bd[sccno[i]][sccno[j]] = min(bd[sccno[i]][sccno[j]], d[i][j] - d[pre[j]][j]);
                        else bd[sccno[i]][sccno[j]] = min(bd[sccno[i]][sccno[j]], d[i][j]);
                    }
                }
            }
        }
        r = sccno[r];
        n = cnt;
        memcpy(d, bd, sizeof(bd));
    }
    cout << res;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. Prufer序列

P6086 【模板】Prüfer 序列


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 5e6 + 10;
int f[N], p[N], out[N];
void solve() {
    int n, op;
    ll res = 0;
    cin >> n >> op;
    if (op == 1) {
        for (int i = 1; i <= n - 1; ++i) {
            cin >> f[i];
            out[f[i]]++;
        }
        for (int i = 0, j = 1; i <= n - 2; ++j) {
            while (out[j]) j++;
            p[++i] = f[j];
            while (i <= n - 2 && --out[p[i]] == 0 && p[i] < j) p[i + 1] = f[p[i]], i++;
        }
        for (int i = 1; i <= n - 2; ++i) res ^= 1ll * i * p[i];
    }
    else {
        for (int i = 1; i <= n - 2; ++i) {
            cin >> p[i];
            out[p[i]]++;
        }
        p[n - 1] = n;
        out[p[n - 1]]++;
        for (int i = 0, j = 1; i <= n - 1; ++j) {
            while (out[j]) j++;
            f[j] = p[++i];
            while (i <= n - 1 && --out[p[i]] == 0 && p[i] < j) f[p[i]] = p[i + 1], i++;
        }
        for (int i = 1; i <= n - 1; ++i) res ^= 1ll * i * f[i];
    }
    cout << res;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}

Cayley 公式:完全图有棵生成树。

  1. 仙人掌

P5236 【模板】静态仙人掌


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e4 + 10;
struct edge {
    int u, v, w;
};
vector<vector<edge> >e(N);
vector<vector<edge> >p(N);
int newn, s[N];
int num[N], low[N], dfn, fa[N], fw[N];
int f[N][15], deep[N], dis[N], A, B;
void build(int u, int v, int w) {
    newn++;
    int tmp = v, sum = w;
    while (tmp != u) {
        s[tmp] = sum;
        sum += fw[tmp];
        tmp = fa[tmp];
    }
    s[newn] = s[u] = sum;
    tmp = v;
    while (tmp != u) {
        p[newn].push_back({ newn,tmp,min(s[tmp],s[u] - s[tmp]) });
        tmp = fa[tmp];
    }
    p[u].push_back({ u,newn,0 });
}
void tarjan(int x, int father) {
    num[x] = low[x] = ++dfn;
    for (auto i : e[x]) {
        int v = i.v, w = i.w;
        if (!num[v]) {
            fa[v] = x, fw[v] = w;
            tarjan(v, x);
            low[x] = min(low[x], low[v]);
            if (num[x] < low[v])  p[x].push_back({ x,v,w });
        }
        else if (v != father) low[x] = min(low[x], num[v]);
    }
    for (auto i : e[x]) {
        int v = i.v, w = i.w;
        if (num[x] < num[v] && fa[v] != x) build(x, v, w);
    }
}
void dfs(int x, int father) {
    deep[x] = deep[father] + 1;
    f[x][0] = father;
    for (int i = 1; (1 << i) <= deep[x]; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
    for (auto i : p[x]) {
        int v = i.v;
        dis[v] = dis[x] + i.w;
        if (v != father) dfs(v, x);
    }
}
int lca(int x, int y) {
    if (deep[x] < deep[y]) swap(x, y);
    for (int i = 14; i >= 0; --i) {
        if (deep[f[x][i]] >= deep[y]) x = f[x][i];
    }
    if (x == y) return x;
    for (int i = 14; i >= 0; --i) {
        if (f[x][i] != f[y][i]) {
            x = f[x][i];
            y = f[y][i];
        }
    }
    A = x, B = y;
    return f[x][0];
}
void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    newn = n;
    for (int i = 1; i <= m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back({ u,v,w });
        e[v].push_back({ v,u,w });
    }
    tarjan(1, 0);
    dfs(1, 0);
    for (int i = 1; i <= q; ++i) {
        int a, b;
        cin >> a >> b;
        int d = lca(a, b);
        if (d <= n) cout << dis[a] + dis[b] - dis[d] * 2 << '\n';
        else cout << dis[a] + dis[b] - dis[A] - dis[B] + min(abs(s[A] - s[B]), s[d] - abs(s[A] - s[B])) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 双端队列

P4667 [BalticOI 2011 Day1]Switch the Lamp On


#include <iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e2 + 10;
struct node {
    int x, y, dis;
};
int n, m;
int g[N][N], dis[N][N];
int d[4][2] = { {-1,-1},{-1,1},{1,-1},{1,1} }, ab[4] = { 2,1,1,2 }, cd[4][2] = { {-1,-1},{-1,0},{0,-1},{0,0} };
void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[1][1] = 0;
    deque<node> dq;
    dq.push_back({ 1,1,0 });
    while (!dq.empty()) {
        node u = dq.front();
        dq.pop_front();
        for (int i = 0; i < 4; ++i) {
            int nx = u.x + d[i][0], ny = u.y + d[i][1];
            int k = g[u.x + cd[i][0]][u.y + cd[i][1]] != ab[i];
            if (nx >= 1 && nx <= n + 1 && ny >= 1 && ny <= m + 1 && dis[nx][ny] > dis[u.x][u.y] + k) {
                dis[nx][ny] = dis[u.x][u.y] + k;
                if (k == 0) dq.push_front({ nx,ny,dis[nx][ny] });
                else dq.push_back({ nx,ny,dis[nx][ny] });
                if (nx == n + 1 && ny == m + 1) break;
            }
        }
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            char ch;
            cin >> ch;
            if (ch == '/') g[i][j] = 1;
            else g[i][j] = 2;
        }
    }
    bfs();
    if (dis[n + 1][m + 1] == 0x3f3f3f3f) cout << "NO SOLUTION";
    else cout << dis[n + 1][m + 1];
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 模拟退火

P4044 [AHOI2014/JSOI2014]保龄球


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e2 + 10;
struct {
    int x, y;
}a[N];
int n, f = 0, ans = 0;
int calc() {
    int res = 0;
    for (int i = 0; i < n; ++i) {
        res += a[i].x + a[i].y;
        if (i < n - 1) {
            if (a[i].x == 10) res += a[i + 1].x + a[i + 1].y;
            else if (a[i].x + a[i].y == 10) res += a[i + 1].x;
        }
    }
    ans = max(ans, res);
    return res;
}
void sa() {
    for (double t = 1e4; t > 1e-4; t *= 0.99) {
        int d1 = calc();
        int x = rand() % n, y = rand() % n;
        swap(a[x], a[y]);
        if (f && a[n - 2].x != 10 || !f && a[n - 1].x == 10) swap(a[x], a[y]);
        else {
            int d2 = calc();
            if (exp((d2 - d1) / t) < (double)rand() / RAND_MAX) swap(a[x], a[y]);
        }
    }
}
void solve() {
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> a[i].x >> a[i].y;
    if (a[n - 1].x == 10) {
        n++;
        f = 1;
        cin >> a[n - 1].x >> a[n - 1].y;
    }
    while ((double)clock() / CLOCKS_PER_SEC < 0.8) sa();
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 爬山法

P4035 [JSOI2008]球形空间产生器


#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
using namespace std;
#define ll long long 
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e1 + 10;
int n;
double a[N][N], ans[N], dis[N], delta[N];
void calc() {
    double avg = 0;
    for (int i = 1; i <= n + 1; ++i) {
        dis[i] = delta[i] = 0;
        for (int j = 1; j <= n; ++j) {
            dis[i] += (a[i][j] - ans[j]) * (a[i][j] - ans[j]);
        }
        dis[i] = sqrt(dis[i]);
        avg += dis[i] / (n + 1);
    }
    for (int i = 1; i <= n + 1; ++i) {
        for (int j = 1; j <= n; ++j) {
            delta[j] += (dis[i] - avg) * (a[i][j] - ans[j]) / avg;
        }
    }
}
void solve() {
    cin >> n;
    for (int i = 1; i <= n + 1; ++i) {
        for (int j = 1; j <= n; ++j) {
            cin >> a[i][j];
            ans[j] += a[i][j] / (n + 1);
        }
    }
    for (double t = 1e4; t > 1e-4; t *= 0.99995) {
        calc();
        for (int i = 1; i <= n; ++i) ans[i] += delta[i] * t;
    }
    for (int i = 1; i <= n; ++i) cout << setiosflags(ios::fixed) << setprecision(3) << ans[i] << " ";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值