图论模板

最短路(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  阅读(6)  评论(0编辑  收藏  举报
  1. 1 青春コンプレックス 結束バンド
  2. 2 ギターと孤独と蒼い惑星 結束バンド
  3. 3 星座になれたら 結束バンド
  4. 4 恋のうた (feat. 由崎司) 鬼頭明里
  5. 5 月と星空 カノエラナ
  6. 6 Cagayake!GIRLS[5人Ver.] (TV size Ver.) 桜高軽音部
  7. 7 不可思議のカルテ 不可思議のカルテ
  8. 8 優しさの理由 ChouCho
青春コンプレックス - 結束バンド
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 樋口愛

作曲 : 音羽-otoha-

编曲 : 三井律郎

暗く狭いのが好きだった 深く被るフードの中

喜欢黑暗狭窄的地方 如被深深掩盖的兜帽之中

無情な世界を恨んだ目は どうしようもなく愛を欲してた

对眼中无情的世界恨之入骨 却无可救药地想得到爱

雨に濡れるのが好きだった 曇った顔が似合うから

雨に濡れるのが好きだった 曇った顔が似合うから

雨に濡れるのが好きだった 曇った顔が似合うから

喜欢被雨淋湿 因为这才符合我阴沉的脸

嵐に怯えてるフリをして 空が割れるのを待っていたんだ

假装着害怕暴风雨 又等待着天空的破裂

かき鳴らせ 光のファズで 雷鳴を 轟かせたいんだ

奏响吧 以光的法兹让雷鸣声轰鸣

打ち鳴らせ 痛みの先へ どうしよう! 大暴走獰猛な鼓動を

敲响吧 苦痛的前方该如何! 以这狂暴凶猛的心跳回应吧

悲しい歌ほど好きだった 優しい気持ちになれるから

悲しい歌ほど好きだった 優しい気持ちになれるから

悲しい歌ほど好きだった 優しい気持ちになれるから

尤为喜欢听忧伤的歌曲 因为会让心情变得平和下来

明るい場所を求めていた だけど触れるのは怖かった

渴求着明亮的地方 但是也害怕着触碰光明

深く潜るのが好きだった 海の底にも月があった

喜欢潜入深海之中 因为海底之下也有月亮

誰にも言わない筈だった が 歪な線が闇夜を走った

本来应该不会和任何人提起 但扭曲的线条却在黑夜里奔跑

かき鳴らせ 交わるカルテット 革命を 成し遂げてみたいな

奏响吧 这交响的四重奏 试着完成这革命

打ち鳴らせ 嘆きのフォルテ どうしよう? 超奔放凶暴な本性を

敲响吧 叹息的加强符该如何? 这奔放且狂暴至极的本性啊

私 俯いてばかりだ

私 俯いてばかりだ

私 俯いてばかりだ

我 一直低着头

それでいい 猫背のまま 虎になりたいから

那样就好 因为成为一只驼背的老虎正如我所愿啊

かき鳴らせ 光のファズで 雷鳴を 轟かせたいんだ

かき鳴らせ 光のファズで 雷鳴を 轟かせたいんだ

かき鳴らせ 光のファズで 雷鳴を 轟かせたいんだ

奏响吧 以光的法兹让雷鸣声轰鸣

打ち鳴らせ 痛みの先へ さあいこう 大暴走獰猛な鼓動を

敲响吧 向着苦痛的前方冲吧 这暴走凶猛的心跳

衝動的感情 吠えてみろ!

冲动的感情 咆哮吧!

かき鳴らせ

奏响吧

雷鳴を这雷鸣