• [CF Round603 Div2 F]Economic Difficulties


    题目:Economic Difficulties

    传送门:https://codeforces.com/contest/1263/problem/F

    题意:给了两棵tree:Ta(拥有a个节点,节点编号为[n+1, n+a]) Tb(拥有b个节点, 节点编号: [n+ a + 1, n + a + b]) 其中两颗tree的叶子节点按照dfs序依次连续连向 $ i, i in [1, n] $节点,询问最多可以去掉多少的tree上节点,使得每一个$i , i in [1, n]$ 仍然可以连通Ta,或者Tb的根节点。

    分析:

    1.做法一:https://codeforces.com/blog/entry/71844?locale=en

    类似泛化背包,每个物品要么选择a,要么选择b,连续选择有额外贡献,假设cost_a[i,j]代表[i,j]区间选择a的贡献,cost_b[i,j]代表[i,j]区间选择b的贡献。

    dp[i]代表前i个节点,方程:$$ dp[i] = max{dp[j] + cost[j+1,i] }$$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 vector< vector<int> > calc_cost(int vn, int n, vector<int> fa, vector<int> tg) {
     5     vector< vector<int> > res(n+1, vector<int>(n+1));
     6     for (int l = 1; l <= n; l++) {
     7         vector<int> deg(vn+1);
     8         for (int i = 2; i <= vn ; i++) deg[fa[i]]++;
     9         int val = 0;
    10         for (int r = l; r <= n; r++) {
    11             for(int v = tg[r]; v != 1 && deg[v] == 0; --deg[v = fa[v]]) 
    12                 val++;
    13             res[l][r] = val;
    14         }
    15     }
    16     return res;
    17 }
    18 
    19 int main() {
    20     int n;
    21     scanf("%d", &n);
    22     vector< vector<int> > cost[2];
    23     for (int j = 0; j < 2; j++) {
    24         int vn;
    25         scanf("%d", &vn);
    26         vector<int> fa(vn+1);
    27         vector<int> tg(n+1);
    28         for (int i = 2; i <= vn; i++) scanf("%d", &fa[i]);
    29         for (int i = 1; i <= n;  i++)  scanf("%d", &tg[i]);
    30         cost[j] = calc_cost(vn, n, fa, tg);
    31     }
    32     
    33     vector<int> dp(n + 1, 0);
    34     for (int i = 1; i <= n; i++) 
    35         for (int j = 0; j < i; j++) 
    36             dp[i] = max(dp[i], dp[j] + max(cost[0][j+1][i], cost[1][j+1][i]));
    37     printf("%d", dp[n]);
    38     return 0;
    39 }
    View Code

    2.基于最后的结果,我们肯定是选择Ta和Tb的一些节点,去除这些节点及其后代节点,考虑到这里,我们只要把每个节点控制的区间算出来,然后按照左端点或者有端点排序,然后做限制背包dp。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 1e4 + 7;
    const int INF = 1e9 + 7;
    vector< pair<pair<int,int>, int> > vec;
    int sz[MAXN], st[MAXN], ed[MAXN], tg[MAXN];
    vector<int> G[MAXN];
    void dfs(int u) {
        sz[u] = 1;
        st[u] = INF; ed[u] = -INF;
        if(tg[u]) st[u] = ed[u] = tg[u];
        for(auto v : G[u]) {
            dfs(v);
            sz[u] += sz[v];
            st[u] = min(st[u], st[v]);
            ed[u] = max(ed[u], ed[v]);
        }
        vec.push_back(make_pair(make_pair(ed[u], st[u] - 1), sz[u]-(u == 1)));
    }
    int dp[MAXN];
    int main() {
        int n, a, x;
        scanf("%d", &n);
        for(int j = 0; j < 2; j++) { 
            scanf("%d", &a);
            for(int i = 2;i <= a; i++) {
                scanf("%d", &x);
                G[x].push_back(i);
            }
            for(int i = 1; i <= n; i++) {
                scanf("%d", &x);
                tg[x] = i;
            }
            dfs(1);
            for(int i = 1; i <= a; i++) {
                G[i].clear();
                tg[i] = 0;
            }
        }
        sort(vec.begin(), vec.end());
        for(auto it : vec) {
            int l = it.first.second, r = it.first.first;
            dp[r] = max(dp[r], dp[l] + it.second);
        }
        printf("%d", dp[n]);
        return 0;
    }

    3.和文理分科类似,该题也可以用网络流求解,然而我到现在都不知道为啥是对的。

    #include <bits/stdc++.h>
    using namespace std;
    typedef int LL;
    const int MAXN = 1e5 + 7;
    const int MAXM = 1e5 + 7;
    const int INF = 1e9 + 7;
    
    namespace NWF {
        struct Edge {
            int to, nxt;LL f;
        } e[MAXM << 1]; 
        int S, T, tot;
        int ecnt, head[MAXN], cur[MAXN], dis[MAXN];
        queue<int> q;
        void init(int _S, int _T, int _tot){
            ecnt = 1; S = _S; T = _T; tot = _tot;
            memset(head, 0, (tot + 1) * sizeof(int));
        } 
        void addEdge(int u, int v, LL f) {
            e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
            e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
        }
        bool bfs() {
            memset(dis, 0, (tot + 1) * sizeof(int));
            q.push(S); dis[S] = 1;
            while (!q.empty()) {
                int u = q.front(), v; q.pop();
                for (int i = cur[u] = head[u]; i ; i = e[i].nxt) {
                    if (e[i].f && !dis[v = e[i].to]) {
                        q.push(v);
                        dis[v] = dis[u] + 1;
                    }
                }
            }
            return dis[T];
        }
        LL dfs(int u, LL maxf) {
            if (u == T) return maxf;
            LL sumf = maxf;
            for (int &i = cur[u]; i; i = e[i].nxt) {
                if (e[i].f && dis[e[i].to] > dis[u]) {
                    LL tmpf = dfs(e[i].to, min(sumf, e[i].f));
                    e[i].f -= tmpf; e[i ^ 1].f += tmpf;
                    sumf -= tmpf;
                    if (!sumf) return maxf;
                }
            }
            return maxf - sumf;
        }
        LL dinic() {
            LL ret = 0;
            while (bfs()) ret += dfs(S, INF);
            return ret;
        }
    }
    int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
    int main() {
        int n, A, B;
        scanf("%d", &n);
        scanf("%d", &A);
        for(int i = 2;i <= A; i++) scanf("%d", faa+i);
        for(int i = 1; i <= n; i++) scanf("%d", tga + i);
        scanf("%d", &B);
        for(int i = 2;i <= B; i++) scanf("%d", fab+i);
        for(int i = 1; i <= n; i++) scanf("%d", tgb + i);
            
        NWF::init(A+B+1,A+B+2, A+B+3);
        for (int i = 2; i <= A; i++) {
            NWF::addEdge(NWF::S, i, 1);
            NWF::addEdge(faa[i], i, INF);
        }
        for (int i = 2; i <= B; i++) {
            NWF::addEdge(A + i, A + fab[i], INF);
            NWF::addEdge(A + i, NWF::T, 1);
        }
        for (int i = 1; i <= n; i++)
            NWF::addEdge(tga[i], A + tgb[i], INF);
            
        int ans = A - 1 + B - 1 - NWF::dinic();
        printf("%d", ans);
        return 0;
    }
    View Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef int LL;
    const int MAXN = 1e5 + 7;
    const int MAXM = 1e5 + 7;
    const int INF = 1e9 + 7;
    
    namespace NWF {
        struct Edge{
            int to, nxt;LL f;
        }e[MAXM << 1];
        int S, T, tot;
        int ecnt, head[MAXN], cur[MAXN], pre[MAXN], num[MAXN], dis[MAXN];
        queue<int> q;
        void init(int _S, int _T, int _tot){
            ecnt = 1; S = _S; T = _T; tot = _tot;
            memset(num,  0, (tot + 1) * sizeof(int));
            memset(head, 0, (tot + 1) * sizeof(int));
        } 
        inline void addEdge(int u, int v, LL f) {
            e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
            e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
        }
        void bfs() {
            memset(dis, 0, (tot + 1) * sizeof(int));
            q.push(T);
            dis[T] = 1;
            while(!q.empty()) {
                int u = q.front(), v; q.pop();
                num[dis[u]]++;
                for(int i = cur[u] = head[u]; i; i = e[i].nxt) {
                    if(!dis[v = e[i].to]) {
                        dis[v] = dis[u] + 1;
                        q.push(v);
                    }
                }
            }
        }
        LL augment() {
            LL flow = INF;
            for(int i = S; i != T; i = e[cur[i]].to) 
                flow = min(flow, e[cur[i]].f);
            for(int i = S; i != T; i = e[cur[i]].to) {
                e[cur[i]].f -= flow;
                e[cur[i] ^ 1].f += flow;
            }
            return flow;
        }
        LL isap() {
            bfs();
            int u = S, v;
            LL flow = 0;
            while(dis[S] <= tot) {
                if(u == T) {
                    flow += augment();
                    u = S;
                }
                bool fg = 0;
                for(int i = cur[u]; i; i = e[i].nxt) {
                    if(e[i].f && dis[u] > dis[v = e[i].to]) {
                        pre[v] = u;
                        cur[u] = i;
                        u = v;
                        fg = 1;
                        break;
                    }
                }
                if(fg) continue;
                if(!--num[dis[u]]) break;
                int maxDis = tot;
                for(int i = head[u]; i; i = e[i].nxt) {
                    if(e[i].f && maxDis > dis[v = e[i].to]) {
                        maxDis = dis[v];
                        cur[u] = i;
                    }
                }
                num[dis[u] = maxDis + 1]++;
                if(u != S) u = pre[u];
            }
            return flow;
        }
    }
    int faa[MAXN], fab[MAXN], tga[MAXN], tgb[MAXN];
    int main() {
        int n, A, B;
        scanf("%d", &n);
        scanf("%d", &A);
        for(int i = 2;i <= A; i++) scanf("%d", faa+i);
        for(int i = 1; i <= n; i++) scanf("%d", tga + i);
        scanf("%d", &B);
        for(int i = 2;i <= B; i++) scanf("%d", fab+i);
        for(int i = 1; i <= n; i++) scanf("%d", tgb + i);
            
        NWF::init(A+B+1,A+B+2, A+B+3);
        for (int i = 2; i <= A; i++) {
            NWF::addEdge(NWF::S, i, 1);
            NWF::addEdge(faa[i], i, INF);
        }
        for (int i = 2; i <= B; i++) {
            NWF::addEdge(A + i, A + fab[i], INF);
            NWF::addEdge(A + i, NWF::T, 1);
        }
        for (int i = 1; i <= n; i++)
            NWF::addEdge(tga[i], A + tgb[i], INF);
            
        int ans = A - 1 + B - 1 - NWF::isap();
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    Vim 在 windows 环境下的初步配置
    空间向量在任意平面的投影公式推导 (矩阵方法)
    jquery中获取元素的几种方式小结
    开源框架
    将插入的新行放入dataGridView的第一行
    go-mod 入门
    docker 常用启动命令
    golang str 首字母大写
    遇到过的几个难搞的问题
    jwt、session、oauth 异同
  • 原文地址:https://www.cnblogs.com/hjj1871984569/p/11973734.html
Copyright © 2020-2023  润新知