zoukankan      html  css  js  c++  java
  • CF 976F 递增容量最大流

    给你一个二分图 要求你求出对于k=[0~Mindegree] 每个点的度数至少为k所需要的最少边数 并输出方案

    如果是单个询问的话 直接跑一个下界网络流即可 但是有多个询问 重建图强行跑不行

    反过来考虑,变成至多能删除多少边则建边[s,i,degree[i]-Mindegree] [i,T,degree[i]-Mindegree] [u,v,1]

    这样跑出来的流 二分图中没有流量的边代表是要选的 有流量的是要删的 同时保证了每个点的度数不小于Mindegree

    则接下来每次对与S,T相连的边容量++ 得到k=[0~Mindegree-1]的答案

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 4050;
    const int MAXM = 10005;
    const int INF = 1000000050;
    int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], f[MAXM << 1], ed = 1, S, T;
    inline void addedge(int u, int v, int cap)
    {
        to[++ed] = v;
        nxt[ed] = Head[u];
        Head[u] = ed;
        f[ed] = cap;
        to[++ed] = u;
        nxt[ed] = Head[v];
        Head[v] = ed;
        f[ed] = 0;
        return;
    }
    inline bool BFS()
    {
        int u;
        memset(lev, -1, sizeof(lev));
        queue<int>q;
        lev[S] = 0;
        q.push(S);
        while (q.size()) {
            u = q.front();
            q.pop();
            for (int i = Head[u]; i; i = nxt[i])
                if (f[i] && lev[to[i]] == -1) {
                    lev[to[i]] = lev[u] + 1;
                    q.push(to[i]);
                    /*
                    if (to[i] == T)
                    {
                            return 1;
                    }
                    magic one way optimize
                    */
                }
        }
        memcpy(cur, Head, sizeof Head);
        return lev[T] != -1;
    }
    inline int DFS(int u, int maxf)
    {
        if (u == T || !maxf) {
            return maxf;
        }
        int cnt = 0;
        for (int &i = cur[u], tem; i; i = nxt[i])
            if (f[i] && lev[to[i]] == lev[u] + 1) {
                tem = DFS(to[i], min(maxf, f[i]));
                maxf -= tem;
                f[i] -= tem;
                f[i ^ 1] += tem;
                cnt += tem;
                if (!maxf) {
                    break;
                }
            }
        if (!cnt) {
            lev[u] = -1;
        }
        return cnt;
    }
    int Dinic()
    {
        int ans = 0;
        while (BFS()) {
            ans += DFS(S, 2147483647);
        }
        return ans;
    }
    void init(int SS, int TT)
    {
        memset(Head, 0, sizeof(Head));
        ed = 1;
        S = SS;
        T = TT;
        return;
    }
    int du[4005];
    int ans[4005][4005];
    int main()
    {
        int n1, n2, m;
        int u, v;
        scanf("%d %d %d", &n1, &n2, &m);
        int n = n1 + n2;
        for (int i = 1; i <= m; i++) {
            scanf("%d %d", &u, &v);
            addedge(u, v + n1, 1);
            du[u]++, du[v + n1]++;
        }
        int Mindegree = INT_MAX;
        for (int i = 1; i <= n; i++) {
            Mindegree = min(Mindegree, du[i]);
        }
        S = 0, T = n + 1;
        for (int i = 1; i <= n1; i++) {
            addedge(S, i, du[i] - Mindegree);
        }
        for (int i = n1 + 1; i <= n; i++) {
            addedge(i, T, du[i] - Mindegree);
        }
        int ansnow = Dinic();
        for (int x = 1; x <= n1; x++) {
            for (int i = Head[x]; i; i = nxt[i]) {
                v = to[i];
                if (v >= n1 + 1 && v <= n) {
                    if (f[i] == 1) {
                        ans[Mindegree][++ans[Mindegree][0]] = i / 2;
                    }
                }
            }
        }
        for (int i = Head[S]; i; i = nxt[i]) {
            f[i]++;
        }
        for (int x = n1 + 1; x <= n; x++) {
            for (int i = Head[x]; i; i = nxt[i]) {
                v = to[i];
                if (v == T) {
                    f[i]++;
                }
            }
        }
        for (int i = Mindegree - 1; i >= 0; i--) {
            ansnow = Dinic();
            for (int x = 1; x <= n1; x++) {
                for (int j = Head[x]; j; j = nxt[j]) {
                    v = to[j];
                    if (v >= n1 + 1 && v <= n) {
                        if (f[j] == 1) {
                            ans[i][++ans[i][0]] = j / 2;
                        }
                    }
                }
            }
            for (int j = Head[S]; j; j = nxt[j]) {
                f[j]++;
            }
            for (int x = n1 + 1; x <= n; x++) {
                for (int j = Head[x]; j; j = nxt[j]) {
                    v = to[j];
                    if (v == T) {
                        f[j]++;
                    }
                }
            }
        }
        for (int i = 0; i <= Mindegree; i++) {
            printf("%d", ans[i][0]);
            for (int j = 1; j <= ans[i][0]; j++) {
                printf(" %d", ans[i][j]);
            }
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1009:带余除法
    1007:计算(a+b)×c的值
    1007:计算(a+b)×c的值
    1007:计算(a+b)×c的值
    1006:A+B问题
    1006:A+B问题
    1006:A+B问题
    C# 运算符 ?、??、?: 、?. 、 各种问号的用法和说明
    C# 运算符 ?、??、?: 、?. 、 各种问号的用法和说明
    在C#中??和?分别是什么意思?
  • 原文地址:https://www.cnblogs.com/Aragaki/p/10672839.html
Copyright © 2011-2022 走看看