模板ACM

最大费用最大流模板(注意和最小的区别仅仅是每条边cost取负,然后最后答案取负)

c 复制代码
int n, m, u, S, T, Ans, cnt, Sum;
int dis[N], x, h[N], cur[N]; bool vis[N];
struct edge { int to, flow, cost, rev; };
vector <edge> G[N];
struct node {
	int x, dis;
	friend bool operator < (node a, node b) { return a.dis > b.dis; }
};

void ins(int x, int y, int w, int l) {
	G[x].pb({y, w, -l, G[y].size()});                 // 最大费用最大流模板,这里要改成-l ,下面是+l,然后最后答案取负即可。
	G[y].pb({x, 0, l, G[x].size() - 1});
}
bool dij() {
	priority_queue <node> Q;
	F(i, 1, cnt) dis[i] = inf; dis[S] = 0; Q.push({S, 0});
	while (Q.size()) {
		node s = Q.top(); Q.pop();
		int k = s.x, v = s.dis;
		if (v > dis[k]) continue;
		for (auto e : G[k])
			if (e.flow && dis[e.to] > dis[k] + e.cost + h[k] - h[e.to]) {
				dis[e.to] = dis[k] + e.cost + h[k] - h[e.to];
				Q.push({e.to, dis[e.to]});
			}
	}
	return dis[T] < inf;
}
int DFS(int k, int flow) {
	if (k == T) return flow;
	int have = 0;
	vis[k] = 1;
	for (int &i = cur[k]; i < G[k].size(); i ++) {
		edge &e = G[k][i];
		if (!vis[e.to] && e.flow && dis[e.to] == dis[k] + e.cost + h[k] - h[e.to]) {
			int now = DFS(e.to, min(flow - have, e.flow));
			e.flow -= now, G[e.to][e.rev].flow += now;
			have += now;
			if (flow == have) break;
		}
	}
	vis[k] = 0;
	return have;
}

map <int, int> H; int w[N];

int calc(int x) {
	int ans = 0;
	for (int y = 2; y * y <= x; y ++)
		while (x % y == 0)
			x /= y, ans ++;
	ans += (x > 1);
	return ans;
}
void doit(int x) {
	if (!H[x]) {
		H[x] = ++ cnt;
		ins(cnt, T, 1, 0);
		w[cnt] = calc(x);
	}
	int v = H[x];
	ins(u, v, 1, w[u] - w[v]);
}

int main() {
//    freopen("data.in","r",stdin);

	R(n), S = 1, T = cnt = 2;
	F(i, 1, n) {
		R(x);
		w[u = ++ cnt] = calc(x);
		ins(S, u, 1, 0);
		for (int j = 1; j * j <= x; j ++) {
			if (x % j == 0) {
				doit(j);
				if (j * j < x)
					doit(x / j);
			}
		}
	}

//	scanf("%d%d%d%d", &n, &m, &S, &T);
//    F(i, 1, m) {
//        scanf("%d%d%d%d", &x, &y, &c, &w);
//        ins(x, y, c, w);
//    }

    Ans = 0;
    while (dij()) {
    	F(i, 1, cnt) cur[i] = 0;
    	int flow = DFS(S, inf);
    	F(i, 1, cnt) h[i] += dis[i];
    	Ans += h[T] * flow;
	}

    printf("%d\n", - Ans);
}

最大流:

c 复制代码
#include <bits/stdc++.h>

#define F(i, a, b) for (int i = (a); i <= (b); ++i)
#define G(i, a, b) for (int i = (a); i >= (b); --i)
#define mem(a, b) memset(a, b, sizeof a)
#define pb push_back
#define putc putchar
#define get getchar()
#define ll long long
#define V vector<int>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

using namespace std;

template <typename Int>
void R(Int &x) {
    char c = get; x = 0; Int t = 1;
    for (; !isdigit(c); c = get) t = (c == '-' ? -1 : t);
    for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get);
    x *= t;
}
template <typename Int>
void W(Int x) {
    if (x < 0) { putc('-'); x = -x; }
    if (x > 9) W(x / 10);
    putc(char(x % 10 + '0'));
}

const int INF = 1e9;

int n, m;
ll c, d;

struct Edge { int to, rev, cap; };

int N, S, T;
vector<vector<Edge>> Gg;
V levelv, cur;

int add_edge(int u, int v, int cap) {
    Edge a{v, (int)Gg[v].size(), cap};
    Edge b{u, (int)Gg[u].size(), 0};
    Gg[u].pb(a);
    Gg[v].pb(b);
    return (int)Gg[u].size() - 1; // 返回 u 侧边下标,便于后续增容
}

bool bfs() {
    fill(levelv.begin(), levelv.end(), -1);
    queue<int> Q;
    levelv[S] = 0; Q.push(S);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        for (auto &e : Gg[u]) if (e.cap > 0 && levelv[e.to] < 0) {
            levelv[e.to] = levelv[u] + 1;
            Q.push(e.to);
        }
    }
    return levelv[T] >= 0;
}

int dfs(int u, int f) {
    if (u == T) return f;
    for (int &i = cur[u]; i < (int)Gg[u].size(); ++i) {
        Edge &e = Gg[u][i];
        if (e.cap > 0 && levelv[e.to] == levelv[u] + 1) {
            int ret = dfs(e.to, min(f, e.cap));
            if (ret > 0) {
                e.cap -= ret;
                Gg[e.to][e.rev].cap += ret;
                return ret;
            }
        }
    }
    return 0;
}

// 在当前残量网络上尽量增广
int maxflow_once() {
    int flow = 0, aug;
    while (bfs()) {
        fill(cur.begin(), cur.end(), 0);
        while ((aug = dfs(S, INF)) > 0) flow += aug;
    }
    return flow;
}

inline void RS(string &s) {
    s.clear();
    char c = get;
    while (isspace(c)) c = get;
    for (; !isspace(c); c = get) s.pb(c);
}

int main() {
    // 输入
    R(n), R(m), R(c), R(d);
    vector<string> a(n);
    F(i, 0, n - 1) RS(a[i]);

    // 统计
    vector<int> rowCnt(n, 0), colCnt(m, 0);
    int E = 0;
    F(i, 0, n - 1) F(j, 0, m - 1)
        if (a[i][j] == '.') { ++rowCnt[i]; ++colCnt[j]; ++E; }

    int maxRow = 0, maxCol = 0;
    F(i, 0, n - 1) maxRow = max(maxRow, rowCnt[i]);
    F(j, 0, m - 1) maxCol = max(maxCol, colCnt[j]);
    int Delta = max(maxRow, maxCol);

    // 建图
    S = 0; T = n + m + 1; N = T + 1;
    Gg.assign(N, {});
    levelv.assign(N, -1);
    cur.assign(N, 0);

    // 记录源->行 与 列->汇 的边下标,便于逐步增容
    V s2r_idx(n), c2t_idx(m);

    // 源->行(初始容量0)
    F(i, 0, n - 1) s2r_idx[i] = add_edge(S, 1 + i, 0);
    // 行->列(空格子为1)
    F(i, 0, n - 1) F(j, 0, m - 1)
        if (a[i][j] == '.') add_edge(1 + i, 1 + n + j, 1);
    // 列->汇(初始容量0)
    F(j, 0, m - 1) c2t_idx[j] = add_edge(1 + n + j, T, 0);

    ll ans = (ll)4e18;
    const ll base = d * 1LL * E; // 常数项
    int totalFlow = 0;

    // k = 0 的代价
    ans = min(ans, base);

    // 逐步把每个行/列容量 +1,并在原残量网络上继续增广
    F(k, 1, Delta) {
        // 行、列容量 +1
        F(i, 0, n - 1) Gg[S][ s2r_idx[i] ].cap += 1;
        F(j, 0, m - 1) Gg[1 + n + j][ c2t_idx[j] ].cap += 1;

        totalFlow += maxflow_once(); // 新能多匹配多少就多送多少

        ll cost = base + (c * 1LL * k - d * 1LL * totalFlow);
        ans = min(ans, cost);

        if (totalFlow == E) break; // 已满匹配,后续只会让 cost 递增 c
    }

    W(ans), putc('\n');
    return 0;
}
相关推荐
Kuo-Teng2 小时前
LeetCode 139: Word Break
java·算法·leetcode·职场和发展·word·动态规划
前端小L2 小时前
图论专题(六):“隐式图”的登场!DFS/BFS 攻克「岛屿数量」
数据结构·算法·深度优先·图论·宽度优先
-大头.2 小时前
Python数据结构之旅:09-图论基础——连接万物的网络
数据结构·图论
sin_hielo2 小时前
leetcode 2654
算法·leetcode
智者知已应修善业3 小时前
【给定英文字符串统计最多小写最前输出】2023-2-27
c语言·开发语言·c++·经验分享·笔记·算法
RWKV元始智能3 小时前
体验RWKV-7训练全过程,只需400行代码训练3分钟
人工智能·算法·机器学习
点云SLAM3 小时前
四元数 (Quaternion)微分-四元数导数的矩阵表示推导(8)
线性代数·算法·计算机视觉·矩阵·机器人·slam·四元数
kyle~4 小时前
算法---贪心算法(Greedy Algorithm)
算法·贪心算法
fashion 道格4 小时前
C 语言数组拼接:从基础实现到细节优化
算法