图论模板

最短路(dijkstra)

无法处理负边权,时间复杂度O(mlogn)

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define eb emplace_back
//#define A puts("Yes")
//#define B puts("No")
#define fi first
#define se second
#define pi pair<ll,ll>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
typedef unsigned int uint;
const int N=1e6+5;
const ll mo=1e9+7;
const int inf=1e9;
//set<int,greater<int>> s;
priority_queue<pair<i64, int>, vector<pair<i64, int>>, greater<pair<i64, int>>> q;
int tot=1,nex[N*2],head[N],to[N],n,m,s,x,y,z;
ll w[N*2],d[N];
bool vis[N];
void add(int x,int y,int z){
	to[++tot]=y; nex[tot]=head[x]; head[x]=tot; w[tot]=z;
}
void dij(int s){
	fo(i,1,n) d[i]=inf;
	d[s]=0;
	q.push(mk(0,s)); 
	while (!q.empty()) {
		x=q.top().se;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x];i;i=nex[i]) {
			int v=to[i];
			if (d[v]>d[x]+w[i]) {
				d[v]=d[x]+w[i];
				q.push(mk(d[v],v));
			}
		}
	}
}
int main() {
//	 freopen("data.in", "r", stdin);
	// 	freopen("data.out","w",stdout);

	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>m>>s;
	fo(i,1,m) {
		cin>>x>>y>>z;
		add(x,y,z);
	}
	
	dij(s);
	fo(i,1,n) cout<<d[i]<<" ";
	
	return 0;
}


abc375_g

判断某条边是不是1到n最短路上的必经边
dis1[x],f[x]分别表示1-x的最短路长度以及在最短路长度限制下到达x的不同路径数量,
dis2,g表示从n出发的

若(x,y)为必经边,则\(dis1[x]+w(x,y)+dis2[y]=dis1[n]\)\(f[x]*g[y]=f[n]\)

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define eb emplace_back
#define pi pair<ll,ll>
#define mk(x,y) make_pair((x),(y))
#define fi first
#define se second
using namespace std;
typedef long long ll;
const ll inf = 1ll << 60;
const int N = 2e5 + 10;
const int mo = 998244353;
const ll mo1 = 1e9 + 7;
const ll mo2 = 1e9 + 9;
ll n, m, x, y, z, w[N * 2], dis1[N], dis2[N];
int tot = 1, to[N * 2], nex[N * 2], head[N], d[N];
pi f[N], g[N];
bool vis[N];
priority_queue<pi, vector<pi>, greater<pi>> q;
void add(int x, int y, ll z) {
    to[++tot] = y; nex[tot] = head[x]; head[x] = tot; w[tot] = z;
}
void dij(int s, pi f[], ll dis[]) {
    fo(i, 1, n) dis[i] = inf, vis[i] = 0;
    dis[s] = 0;
    q.push(mk(0, s));
    while (!q.empty()) {
        x = q.top().se; q.pop();
        if (vis[x]) continue;
        vis[x] = 1;
        for (int i = head[x];i;i = nex[i]) {
            int v = to[i];
            if (dis[v] > dis[x] + w[i]) {
                dis[v] = dis[x] + w[i];
                q.push(mk(dis[v], v));
            }
        }
    }

    fo(i, 1, n) d[i] = 0;
    fo(i, 2, tot) {
        x = to[i]; y = to[i ^ 1]; z = w[i];
        if (dis[x] + w[i] == dis[y]) {
            d[y]++;
        }
    }

    queue<int> q;
    while (!q.empty()) q.pop();
    fo(i, 1, n) if (!d[i]) q.push(i), f[i] = mk(1, 1);

    while (!q.empty()) {
        x = q.front(); q.pop();
        for (int i = head[x];i;i = nex[i]) {
            int v = to[i];
            if (dis[v] == dis[x] + w[i]) {
                d[v]--;
                f[v] = mk((f[v].fi + f[x].fi) % mo1, (f[v].se + f[x].se) % mo2);
                if (!d[v]) q.push(v);
            }
        }
    }
}
bool ans[N * 2];
void solve()
{
    cin >> n >> m;
    fo(i, 1, m) {
        cin >> x >> y >> z;
        add(x, y, z);
        add(y, x, z);
    }

    dij(1, f, dis1);
    dij(n, g, dis2);

    fo(i, 2, tot) {
        x = to[i]; y = to[i ^ 1]; z = w[i];
        if (f[x].fi * g[y].fi % mo1 == f[n].fi && f[x].se * g[y].se % mo2 == f[n].se && dis1[x]+w[i]+dis2[y]==dis1[n]) {

            // cout << x << " " << y << "\n";
            ans[i / 2] = 1;
        }
    }

    fo(i, 1, m) cout << (ans[i] ? "Yes" : "No") << "\n";

}
int main()
{
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int T = 1;
    // cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

Floyed

abc375f
两种操作
1.路径i不再可以通行
2.询问dis(x,y)

显然将询问离线,然后倒着加边,每次加入一条边后,考虑更新。
此时f[x][y]表示的是只通过当前加入的边的情况下,x到y的最短路,那么我们枚举通过新加这条边的路径的两个端点即可。

#include<bits/stdc++.h>
#define ll long long 
#define fo(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for(ll (i)=(a);(i)>=(b);(i)--)
#define eb emplace_back
#define mk make_pair
using namespace std;
const int N = 505;
const int M = 2e5 + 5;
const ll inf = 1ll << 60;
ll f[N][N], n, m, q, ans[M], tot;
bool bz[M];
struct node {
    ll x, y, z;
};
node e[M];
struct key {
    ll op, x, y;
};
key c[M];
void cmin(ll& x, ll y) {
    x = min(x, y);
}
void solve() {
    cin >> n >> m >> q;
    fo(i, 1, m) cin >> e[i].x >> e[i].y >> e[i].z;
    fo(i, 1, q) {
        cin >> c[i].op >> c[i].x;
        if (c[i].op == 2) {
            cin >> c[i].y;
        }
        else bz[c[i].x] = 1;
    }
    fo(i, 1, n) fo(j, 1, n) f[i][j] = inf;
    fo(i, 1, n) f[i][i] = 0;

    fo(i, 1, m) if (!bz[i]) {
        cmin(f[e[i].x][e[i].y], e[i].z);
        cmin(f[e[i].y][e[i].x], e[i].z);
    }

    fo(k, 1, n) fo(i, 1, n) fo(j, 1, n) cmin(f[i][j], f[i][k] + f[k][j]);

    ll id, x, y, z;
    fd(i, q, 1) {
        id = c[i].x;
        x = e[id].x; y = e[id].y; z = e[id].z;

        if (c[i].op == 1) {
            fo(a, 1, n) fo(b, 1, n) {
                cmin(f[a][b], f[a][x] + z + f[y][b]);
                cmin(f[a][b], f[a][y] + z + f[x][b]);
            }
        }
        else {
            x = c[i].x; y = c[i].y;
            if (f[x][y] == inf) ans[++tot] = -1;
            else ans[++tot] = f[x][y];
        }
    }

    fd(i, tot, 1) cout << ans[i] << "\n";

}
int main() {
    //	freopen("data.in","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    // cin>>T;
    while (T--) {
        solve();
    }
    return 0;
}

传递闭包

跟floyed一样,可以采用bitset优化

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define eb emplace_back
using namespace std;
const int N=1005;
typedef long long ll;
bitset<N> b[N];
int n,x;
int main(){
//	freopen("data.in","r",stdin);
	scanf("%d",&n);
	fo(i,1,n) {
		b[i].reset();
		fo(j,1,n) {
			scanf("%d",&x);
			if (x) {
				b[i][j]=1;
			}
		}
	}
	
	fo(k,1,n) {
		fo(i,1,n) if (b[i][k]) b[i]|=b[k];
	}
	
	fo(i,1,n) {
		fo(j,1,n)  {
			printf("%d ",b[i][j]==1?1:0);
		}
		printf("\n");
	}
	return 0;
}

差分约束

[ABC216G] 01Sequence

你需要构造出一个长度为 \(n\)\(01\) 序列,满足 \(m\) 个限制 \((l_i,r_i,x_i)\):在 \([l_i,r_i]\) 这段区间内,序列上 \(1\) 的个数不小于 \(x_i\)你需要保证你的方案中包含 \(1\) 的个数最小。

数据保证有解。

\(1 \le n,m \le 2 \times 10^5\)

\(z_i\)表示1到i中0的数量,那么限制有

  • \(z_i \le z_{i-1}+1\)
  • \(z_{i-1} \le z_{i}\)
  • \(z_{r_i}-z_{l_i-1}\le r_i-l_i+1-x_i\)
  • \(z_0=0\)

将第三个变形,得到\(z_{r_i}\le r_i-l_i+1-x_i+z_{l_i-1}\)
那么我们得到的就是最短路的形式,因为我们求的是\(z_n\)的最大值,最大能够取得就是不等式右边的最小值,所以等价于最短路,因为所有边权都是正的,直接用dij即可。

#include<bits/stdc++.h>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define pi pair<ll,ll>
#define eb emplace_back
//#define A puts("YES")
//#define B puts("NO")
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
//const ll mo1=1e9+7;
//const ll mo2=1e9+9;
const ll mo = 19260817;
const ll P = 131;
const ll Q = 13331;
const ll inf = 1ll << 60;
const int N = 2e5 + 5;
const int M = 1e6 + 5;
int tot = 1, to[M * 2], nex[M * 2], head[N], w[M * 2], d[N];
int n, m;
bool vis[N];
void add(int x, int y, int z) {
    to[++tot] = y; nex[tot] = head[x]; head[x] = tot; w[tot] = z;
}
void dij(int s) {
    priority_queue<pi, vector<pi>, greater<pi>> q;
    fo(i, 1, n) d[i] = n;

    q.push(mk(0, s));
    while (!q.empty()) {
        int x = q.top().se; q.pop();
        if (vis[x]) continue;
        vis[x] = 1;

        for (int i = head[x];i;i = nex[i]) {
            int v = to[i];
            if (d[v] > d[x] + w[i]) {
                d[v] = d[x] + w[i];
                q.push(mk(d[v], v));
            }
        }
    }
}
int main() {
    //	freopen("data.in", "r", stdin);
    //	freopen("data.out", "w", stdout);

    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> m;
    fo(i, 1, n) {
        add(i - 1, i, 1);
        add(i, i - 1, 0);
    }

    int l, r, x;
    fo(i, 1, m) {
        cin >> l >> r >> x;
        add(l - 1, r, r - l + 1 - x);
    }


    dij(0);
    //	fo(i,1,n) cout<<d[i]<<" ";
    //	
    //	return 0;
    fo(i, 1, n) cout << -d[i] + 1 + d[i - 1] << " ";

}

two-sat

[ABC210F] Coprime Solitaire

题面翻译

你有 \(n\) 张卡片,第 \(i\) 张卡片正面写着一个数字 \(a_i\),反面写着一个数字 \(b_i\),现在你可以摆放卡片(规定每张卡片朝上的面),询问是否存在一种摆放方式,使得任意两张不同的卡片朝上面所写的数字都是互质的。

  • 首先有一个非常明显的\(O(N^2)\)的做法,就是直接两两之间根据矛盾关系连边,但是有更好的方法
  • 对于每一个质数,我们都开一个vector记录哪些数有这个质因子,那么这个集合中最多只能选一个数,因此我们可以用前后缀连边优化。
  • 以前缀为例说,\(f[i]\)连向\(f[i-1]\)\(\neg x\),然后\(\neg x\)连向\(f[i-1]\),后缀同理
#include<bits/stdc++.h>
#define fo(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for(ll (i)=(a);(i)>=(b);(i)--)
#define mk(x,y) make_pair((x),(y))
#define pi pair<ll,ll>
#define eb emplace_back 
#define fi first 
#define se second
using namespace std;
typedef long long ll;
const ll mo = 1e9 + 7;
const ll inf = 1ll << 60;
const int N = 2e6 + 5;
int tot, p[N], v[N], a[N * 2],n;
bool vis[N];
vector<int> t[N], e[N];
int dfn[N], low[N], s[N], top, cnt, z, scc[N], num;
bool ins[N];
void tarjan(int x) {
    low[x] = dfn[x] = ++cnt;
    s[++top] = x;
    ins[x] = 1;
    for (int v : e[x]) {
        if (!dfn[v]) {
            tarjan(v);
            low[x] = min(low[x], low[v]);
        }
        else if (ins[v]) low[x] = min(low[x], dfn[v]);
    }
    if (low[x] == dfn[x]) {
        ++num;
        do {
            z = s[top--]; scc[z] = num; ins[z] = 0;
        } while (z != x);
    }
}
void work(int x, int id) {
    int d;
    while (x != 1) {
        d = v[x];
        while (x % d == 0) {
            x /= d;
        }
        t[d].eb(id);
    }
}
int rev(int x) { return x > n ? x - n : x + n; }
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);

    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    fo(i, 2, N - 1) {
        if (!vis[i]) {
            p[++tot] = i;
            v[i] = i;
        }
        fo(j, 1, tot) {
            if (i * p[j] >= N) break;
            vis[i * p[j]] = 1;
            v[i * p[j]] = p[j];
            if (i % p[j] == 0) break;
        }
    }


    cin >> n;
    fo(i, 1, n) {
        cin >> a[i] >> a[i + n];
        work(a[i], i);
        work(a[i + n], i + n);
    }

    int now = 2 * n;
    fo(i, 1, tot) {
        int z = p[i];
        if (!t[z].size()) continue;

        // for (auto x : t[z]) cout << x << " ";
        // cout << "\n";
        now++;
        e[now].eb(rev(t[z][0]));
        for (int j = 1;j < (int)t[z].size();j++) {
            e[t[z][j]].eb(now);
            now++;
            e[now].eb(now - 1);
            e[now].eb(rev(t[z][j]));
        }

        now++;
        e[now].eb(rev(t[z][t[z].size() - 1]));
        for (int j = (int)t[z].size() - 2;j >= 0;j--) {
            e[t[z][j]].eb(now);
            now++;
            e[now].eb(now - 1);
            e[now].eb(rev(t[z][j]));
        }
    }

    fo(i, 1, now) if (!dfn[i]) tarjan(i);

    bool flag = 1;
    fo(i, 1, n) {
        if (a[i] != 1 && a[i + n] != 1) {
            if (scc[i] == scc[i + n]) {
                flag = 0;
            }
        }
    }

    if (flag) cout << "Yes";
    else cout << "No";

    return 0;
}

三元环计数

#include <bits/stdc++.h>
using namespace std;

int n, m, total;
int deg[200001], u[200001], v[200001];
bool vis[200001];

struct Edge {
  int to, nxt;
} edge[200001];

int cntEdge, head[100001];

void addEdge(int u, int v) {
  edge[++cntEdge] = {v, head[u]}, head[u] = cntEdge;
}

int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++)
    scanf("%d%d", u + i, v + i), deg[u[i]]++, deg[v[i]]++;
  for (int i = 1; i <= m; i++) {
    if ((deg[u[i]] == deg[v[i]] && u[i] > v[i]) || deg[u[i]] < deg[v[i]])
      swap(u[i], v[i]);
    addEdge(u[i], v[i]);
  }
  for (int u = 1; u <= n; u++) {
    for (int i = head[u]; i; i = edge[i].nxt) vis[edge[i].to] = true;
    for (int i = head[u]; i; i = edge[i].nxt) {
      int v = edge[i].to;
      for (int j = head[v]; j; j = edge[j].nxt) {
        int w = edge[j].to;
        if (vis[w]) total++;
      }
    }
    for (int i = head[u]; i; i = edge[i].nxt) vis[edge[i].to] = false;
  }
  printf("%d\n", total);
  return 0;
}

四元环计数

#include <bits/stdc++.h>
using namespace std;

int n, m, deg[100001], cnt[100001];
vector<int> E[100001], E1[100001];

long long total;

int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    E[u].push_back(v);
    E[v].push_back(u);
    deg[u]++, deg[v]++;
  }
  for (int u = 1; u <= n; u++)
    for (int v : E[u])
      if (deg[u] > deg[v] || (deg[u] == deg[v] && u > v)) E1[u].push_back(v);
  for (int a = 1; a <= n; a++) {
    for (int b : E1[a])
      for (int c : E[b]) {
        if (deg[a] < deg[c] || (deg[a] == deg[c] && a <= c)) continue;
        total += cnt[c]++;
      }
    for (int b : E1[a])
      for (int c : E[b]) cnt[c] = 0;
  }
  printf("%lld\n", total);
  return 0;
}

最大流

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define eb emplace_back
#define A puts("Yes")
#define B puts("No")
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
// const ll inf=1ll<<60;
const ll mo1=1e9+9;
const ll mo2=1e9+7;
const ll P=131;
const ll Q=13331;
constexpr int inf = 1E9;
template<class T>
struct MaxFlow {
    struct _Edge {
        int to;
        T cap;
        _Edge(int to, T cap) : to(to), cap(cap) {}
    };
    
    int n;
    std::vector<_Edge> e;
    std::vector<std::vector<int>> g;
    std::vector<int> cur, h;
    
    MaxFlow() {}
    MaxFlow(int n) {
        init(n);
    }
    
    void init(int n) {
        this->n = n;
        e.clear();
        g.assign(n, {});
        cur.resize(n);
        h.resize(n);
    }
    
    bool bfs(int s, int t) {
        h.assign(n, -1);
        std::queue<int> que;
        h[s] = 0;
        que.push(s);
        while (!que.empty()) {
            const int u = que.front();
            que.pop();
            for (int i : g[u]) {
				// auto [v, c] = e[i];
				auto v = e[i].to;
				auto c = e[i].cap;
				if (c > 0 && h[v] == -1) {
                    h[v] = h[u] + 1;
                    if (v == t) {
                        return true;
                    }
                    que.push(v);
                }
            }
        }
        return false;
    }
    
    T dfs(int u, int t, T f) {
        if (u == t) {
            return f;
        }
        auto r = f;
        for (int &i = cur[u]; i < int(g[u].size()); ++i) {
            const int j = g[u][i];
			// auto [v, c] = e[j];
			auto v = e[j].to;
			auto c = e[j].cap;
			if (c > 0 && h[v] == h[u] + 1) {
                auto a = dfs(v, t, std::min(r, c));
                e[j].cap -= a;
                e[j ^ 1].cap += a;
                r -= a;
                if (r == 0) {
                    return f;
                }
            }
        }
        return f - r;
    }
    void addEdge(int u, int v, T c) {
        g[u].push_back(e.size());
        e.emplace_back(v, c);
        g[v].push_back(e.size());
        e.emplace_back(u, 0);
    }
    T flow(int s, int t) {
        T ans = 0;
        while (bfs(s, t)) {
            cur.assign(n, 0);
            ans += dfs(s, t, std::numeric_limits<T>::max());
        }
        return ans;
    }
    
    std::vector<bool> minCut() {
        std::vector<bool> c(n);
        for (int i = 0; i < n; i++) {
            c[i] = (h[i] != -1);
        }
        return c;
    }
    
    struct Edge {
        int from;
        int to;
        T cap;
        T flow;
    };
    std::vector<Edge> edges() {
        std::vector<Edge> a;
        for (int i = 0; i < e.size(); i += 2) {
            Edge x;
            x.from = e[i + 1].to;
            x.to = e[i].to;
            x.cap = e[i].cap + e[i + 1].cap;
            x.flow = e[i + 1].cap;
            a.push_back(x);
        }
        return a;
    }
};
int n,m,s,t,x,y,z;
int main(){
   

    cin >> n >> m >> s >> t;
	MaxFlow<ll> mf(n + 2);

    fo(i, 1, m) {
        cin >> x >> y >> z;
        mf.addEdge(x, y, z);
    }

    ll ans = mf.flow(s, t);
    cout << ans;

    return 0;
}
 
 

最小费用最大流

#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define eb emplace_back
#define A puts("Yes")
#define B puts("No")
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
const ll inf=1ll<<60;
const ll mo1=1e9+9;
const ll mo2=1e9+7;
const ll P=131;
const ll Q=13331;
const int N=2e5+5;
struct MCFGraph {
    struct Edge {
        int v, c, f;
        Edge(int v, int c, int f) : v(v), c(c), f(f) {}
    };
    const int n;
    std::vector<Edge> e;
    std::vector<std::vector<int>> g;
    std::vector<i64> h, dis;
    std::vector<int> pre;
    bool dijkstra(int s, int t) {
        dis.assign(n, std::numeric_limits<i64>::max());
        pre.assign(n, -1);
        std::priority_queue<std::pair<i64, int>, std::vector<std::pair<i64, int>>, std::greater<std::pair<i64, int>>> que;
        dis[s] = 0;
        que.emplace(0, s);
        while (!que.empty()) {
            i64 d = que.top().first;
            int u = que.top().second;
            que.pop();
            if (dis[u] < d) continue;
            for (int i : g[u]) {
                int v = e[i].v;
                int c = e[i].c;
                int f = e[i].f;
                if (c > 0 && dis[v] > d + h[u] - h[v] + f) {
                    dis[v] = d + h[u] - h[v] + f;
                    pre[v] = i;
                    que.emplace(dis[v], v);
                }
            }
        }
        return dis[t] != std::numeric_limits<i64>::max();
    }
    MCFGraph(int n) : n(n), g(n) {}
   	void addEdge(int u, int v, int c, int f) { // 最大流
    	g[u].push_back(e.size());
    	e.emplace_back(v, c, f);
    	g[v].push_back(e.size());
    	e.emplace_back(u, 0, -f);
	}
	
    std::pair<int, i64> flow(int s, int t) {
        int flow = 0;
        i64 cost = 0;
        h.assign(n, 0);
        while (dijkstra(s, t)) {
            for (int i = 0; i < n; ++i) h[i] += dis[i];
            int aug = std::numeric_limits<int>::max();
            for (int i = t; i != s; i = e[pre[i] ^ 1].v) aug = std::min(aug, e[pre[i]].c);
            for (int i = t; i != s; i = e[pre[i] ^ 1].v) {
                e[pre[i]].c -= aug;
                e[pre[i] ^ 1].c += aug;
            }
            flow += aug;
            cost += i64(aug) * h[t];
        }
        return std::make_pair(flow, cost);
    }
};
int n,m,s,t,x,y,w,c;
int main(){
//	freopen("data.in","r",stdin);
	
	scanf("%d %d %d %d",&n,&m,&s,&t);
	MCFGraph mf(n+1);
	
	fo(i,1,m) {
		scanf("%d %d %d %d",&x,&y,&w,&c);
		mf.addEdge(x,y,w,c);
	}
	
	pair<int,ll> h=mf.flow(s,t);
	printf("%d %lld", h.fi, h.se);
	

	
	return 0;
}

最大费用可行流

建边时费用取反,剩下的mcmf一样
#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mk(x,y) make_pair((x),(y))
#define eb emplace_back
#define A puts("Yes")
#define B puts("No")
#define fi first
#define se second
#define pi pair<ll,ll>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef long long i64;
const ll inf=1ll<<60;
const ll mo1=1e9+9;
const ll mo2=1e9+7;
const ll P=131;
const ll Q=13331;
const int N=2e5+5;
ll ans=1e9;
struct MCFGraph {
    struct Edge {
        int v, c, f;
        Edge(int v, int c, int f) : v(v), c(c), f(f) {}
    };
    const int n;
    std::vector<Edge> e;
    std::vector<std::vector<int>> g;
    std::vector<i64> h, dis;
    std::vector<int> pre;
    bool dijkstra(int s, int t) {
        dis.assign(n, std::numeric_limits<i64>::max());
        pre.assign(n, -1);
        std::priority_queue<std::pair<i64, int>, std::vector<std::pair<i64, int>>, std::greater<std::pair<i64, int>>> que;
        dis[s] = 0;
        que.emplace(0, s);
        while (!que.empty()) {
            i64 d = que.top().first;
            int u = que.top().second;
            que.pop();
            if (dis[u] < d) continue;
            for (int i : g[u]) {
                int v = e[i].v;
                int c = e[i].c;
                int f = e[i].f;
                if (c > 0 && dis[v] > d + h[u] - h[v] + f) {
                    dis[v] = d + h[u] - h[v] + f;
                    pre[v] = i;
                    que.emplace(dis[v], v);
                }
            }
        }
        return dis[t] != std::numeric_limits<i64>::max();
    }
    MCFGraph(int n) : n(n), g(n) {}
//   	void addEdge(int u, int v, int c, int f) {
//        if (f < 0) {
//            g[u].push_back(e.size());
//            e.emplace_back(v, 0, f);
//            g[v].push_back(e.size());
//            e.emplace_back(u, c, -f);
//        } else {
//            g[u].push_back(e.size());
//            e.emplace_back(v, c, f);
//            g[v].push_back(e.size());
//            e.emplace_back(u, 0, -f);
//        }
//		
//    }
	void addEdge(int u, int v, int c, int f) { // �����
    	g[u].push_back(e.size());
    	e.emplace_back(v, c, f);
    	g[v].push_back(e.size());
    	e.emplace_back(u, 0, -f);
	}
	
    std::pair<ll, i64> flow(int s, int t) {
        int flow = 0;
        i64 cost = 0;
        h.assign(n, 0);
        while (dijkstra(s, t)) {
            for (int i = 0; i < n; ++i) h[i] += dis[i];
            int aug = std::numeric_limits<int>::max();
            for (int i = t; i != s; i = e[pre[i] ^ 1].v) aug = std::min(aug, e[pre[i]].c);
            for (int i = t; i != s; i = e[pre[i] ^ 1].v) {
                e[pre[i]].c -= aug;
                e[pre[i] ^ 1].c += aug;
            }
            flow += aug;
            cost += i64(aug) * h[t];
            ans=min(ans, cost);//与mcmf的区别
        }
        return std::make_pair(flow, cost);
    }
};
int n,m,k,a[105][105],s,t,x,y;
int w[4][2]={
	-1,0,
	1,0,
	0,1,
	0,-1
};
int In(int x,int y){
	return (x-1)*m+y;
}
int Out(int x,int y){
	return (x-1)*m+y+n*m;
}
bool check(int x,int y){
	return (1<=x && x<=n && 1<=y && y<=m && a[x][y]!=-1);
}
int main(){
//	freopen("data.in","r",stdin);
	
	scanf("%d %d %d",&n,&m,&k);
	fo(i,1,n) {
		fo(j,1,m) {
			scanf("%d",&a[i][j]);
		}
	}
	s=2*n*m+1; t=2*n*m+2;

	MCFGraph mf(2*n*m+3);
	fo(i,1,k) {
		scanf("%d %d",&x,&y);
		mf.addEdge(s,In(x,y),1,0);
	}
	
	fo(i,1,k) {
		scanf("%d %d",&x,&y);
		mf.addEdge(Out(x,y),t,1,-100);
	}

	int xx,yy;
	fo(x,1,n) fo(y,1,m) {
		if (a[x][y]==-1) continue;
		mf.addEdge(In(x,y),Out(x,y),1,1-a[x][y]);
		fo(k,0,3) {
			xx=x+w[k][0];
			yy=y+w[k][1];
			if (check(xx,yy)) {
				mf.addEdge(Out(x,y),In(xx,yy),1,0);
			}
		}
	}
	pi h=mf.flow(s,t);

	printf("%lld\n",max(-ans,0ll));
	
	
	
	return 0;
}

posted @ 2024-10-21 22:22  gan_coder  阅读(22)  评论(0)    收藏  举报