P2050 [NOI2012]美食节

本文深入探讨了修车数据加强版算法的实现细节,包括动态加边加点的处理方式,通过C++代码详细解释了算法流程,涵盖了BFS、DFS、Augment等关键步骤,展示了如何在复杂网络中寻找最小成本最大流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

修车数据加强版 需要动态加边加点

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x7f7f7f7f;
const int MAXN = 100005, MAXM = 5000005;
int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], f[MAXM << 1], mono[MAXM << 1], ed = 1, S, T;
int pre[MAXN];
int t[105][105];
int n, m, sum, now;
bool exist[MAXN];
void addedge(int u, int v, int cap, int val) {
        to[++ed] = v;
        nxt[ed] = Head[u];
        Head[u] = ed;
        f[ed] = cap;
        mono[ed] = val;
        to[++ed] = u;
        nxt[ed] = Head[v];
        Head[v] = ed;
        f[ed] = 0;
        mono[ed] = -1 * val;
        return;
}
bool BFS() {
        int u;
        queue<int>q;
        memset(exist, false, sizeof(exist));
        memset(lev, 127, sizeof(lev));
        lev[S] = pre[S] = 0;
        q.push(S);
        while (q.size()) {
                u = q.front();
                q.pop();
                exist[u] = false;
                for (int i = Head[u]; i; i = nxt[i])
                        if (f[i] && lev[u] + mono[i] < lev[to[i]]) {
                                lev[to[i]] = lev[u] + mono[i];
                                pre[to[i]] = i;
                                if (!exist[to[i]]) {
                                        exist[to[i]] = true;
                                        q.push(to[i]);
                                }
                        }
        }
        memcpy(cur, Head, sizeof(Head));
        return lev[T] != INF;
}
int DFS(int u, int maxf) {
        if (u == T || !maxf) {
                return maxf;
        }
        exist[u] = true;
        int cnt = 0;
        for (int &i = cur[u], tem; i; i = nxt[i])
                if (f[i] && lev[u] + mono[i] == lev[to[i]]) {
                        if (exist[to[i]]) {
                                continue;
                        }
                        tem = DFS(to[i], min(f[i], maxf));
                        maxf -= tem;
                        f[i] -= tem;
                        f[i ^ 1] += tem;
                        cnt += tem;
                        if (!maxf) {
                                break;
                        }
                }
        if (!cnt) {
                lev[u] = -1 * INF;
        }
        exist[u] = false;
        return cnt;
}
int Augment() {
        int delta = INF;
        for (int i = pre[T]; i; i = pre[to[i ^ 1]])
                if (f[i] < delta) {
                        delta = f[i];
                }
        for (int i = pre[T]; i; i = pre[to[i ^ 1]]) {
                f[i] -= delta;
                f[i ^ 1] += delta;
        }
        return delta * lev[T];
}
int MCMF() {
        int ans = 0;
        memset(exist, false, sizeof(exist));
        while (BFS())
                //ans+=DFS(S,INF)*lev[T];
        {
                int j = to[pre[T] ^ 1];
                addedge(j + 1, T, 1, 0);
                j++;
                for (int i = 1; i <= n; i++) {
                        int x = (j - n - 1) / sum + 1;
                        int y = j - n - (x - 1) * sum;
                        addedge(i, j, 1, y * t[x][i]);
                }
                ans += Augment();
        }
        return ans;
}
int main() {
        sum = 0;
        scanf("%d %d", &n, &m);
        S = 0;
        for (int i = 1; i <= n; i++) {
                scanf("%d", &now);
                sum += now;
                addedge(S, i, now, 0);
        }
        T = n + sum * m + 1;
        for (int i = n + 1; i <= T - 1; i += sum) {
                addedge(i, T, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                        scanf("%d", &t[j][i]);
                }
        }
        for (int i = 1; i <= n; i++) {
                for (int j = n + 1; j <= T - 1; j += sum) {
                        int x = (j - n - 1) / sum + 1;
                        int y = j - n - (x - 1) * sum;
                        addedge(i, j, 1, y * t[x][i]);
                }
        }
        int ans = MCMF();
        cout << ans << endl;
        return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Aragaki/p/10686095.html

### NOI2012 三重镇问题分析 在NOI2012竞赛中,"三重镇"问题是一个典型的组合数学与动态规划结合的题目。题目要求计算在特定条件下,某些组合的数量。解题的关键在于对组合数学和动态规划状态设计的深入理解。 #### 问题概述 题目要求在一个由 $n$ 个点构成的图中,将这些点连接成若干边,使得图中满足以下条件: 1. 每条边的权重是 $1$ 或 $2$。 2. 每个点的度数(即与该点相连的边的数量)必须是 $3$。 3. 所有点的度数总和必须等于 $2m$,其中 $m$ 是边的数量。 目标是计算满足这些条件的图的数量。 #### 解题思路 问题的核心是组合数学与动态规划的结合。通过分析,可以将问题拆解为以下几个关键步骤: 1. **度数分配**:首先,需要确定每个点的度数为 $3$。由于每个边的权重为 $1$ 或 $2$,因此需要将度数分配到边中,并确保总和为 $2m$。 2. **边权重分配**:对于每一条边,其权重可以是 $1$ 或 $2$。需要确保所有边的权重总和等于 $m$。 3. **组合计算**:通过动态规划的方法,计算满足条件的图的数量。 #### 动态规划状态设计 动态规划的状态设计是问题的核心。可以定义一个二维数组 $dp[i][j]$,其中: - $i$ 表示已经处理了前 $i$ 个点。 - $j$ 表示当前边的权重总和为 $j$。 状态转移方程为: - 对于每个点 $i$,其度数必须为 $3$。假设当前点的度数分配为 $k$,则需要从剩余的边中选择 $k$ 条边。 - 对于每条边,其权重可以是 $1$ 或 $2$。因此,状态转移需要考虑不同的权重分配情况。 #### 代码实现 以下是一个简化的动态规划实现示例,用于计算满足条件的图的数量: ```python # 初始化动态规划数组 MOD = 10**9 + 7 max_points = 100 # 假设最多有100个点 max_weight = 200 # 假设最大权重总和为200 dp = [[0] * (max_weight + 1) for _ in range(max_points + 1)] dp[0][0] = 1 # 初始状态:0个点,权重总和为0 # 动态规划状态转移 for i in range(1, max_points + 1): for j in range(max_weight + 1): # 对于每个点,度数必须为3 for k in range(1, 4): # 假设k为当前点的度数 if j - k >= 0: dp[i][j] = (dp[i][j] + dp[i-1][j-k]) % MOD # 输出结果 print(dp[max_points][max_weight]) ``` #### 复杂度分析 该动态规划算法的时间复杂度为 $O(n \cdot m \cdot k)$,其中 $n$ 是点的数量,$m$ 是边的权重总和,$k$ 是每个点的度数可能的取值范围。通过优化状态转移,可以进一步降低复杂度。 #### 总结 NOI2012 "三重镇" 问题通过组合数学与动态规划的结合,展示了如何处理复杂的约束条件。关键在于对度数分配和边权重分配的细致分析,以及动态规划状态的设计与实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值