• 贿赂FIPA(阶段内转移无后效)⭐


    题面

    FIPA(国际国际计划协会联合会)近期将进行投票,以确定下一届IPWC(国际规划世界杯)的主办方。

    钻石大陆的代表本内特希望通过以赠送钻石买通国家的方式,获得更多的投票。

    当然,他并不需要买通所有的国家,因为小国家会跟随着他们附庸的大国进行投票。

    换句话说,只要买通了一个大国,就等于获得了它和它统治下所有小国的投票。

    例如,C在B的统治下,B在A的统治下,那么买通A就等于获得了三国的投票。

    请注意,一个国家最多附庸于一个国家的统治下,附庸关系也不会构成环。

    请你编写一个程序,帮助本内特求出在至少获得m个国家支持的情况下的最少花费是多少。

    输入格式

    输入包含多组测试数据。

    第一行包含两个整数n和m,其中n表示参与投票的国家的总数,m表示获得的票数。

    接下来n行,每行包含一个国家的信息,形式如下:

    CountryName DiamondCount DCName DCName …

    其中CountryName是一个长度不超过100的字符串,表示这个国家的名字,DiamondCount是一个整数,表示买通该国家需要的钻石数,DCName是一个字符串,表示直接附庸于该国家的一个国家的名字。

    一个国家可能没有任何附庸国家。

    当读入一行为#时,表示输入终止。

    输出格式

    每组数据输出一个结果,每个结果占一行。

    3数据范围

    1≤n≤200,
    0≤m≤n

    输入样例:

    3 2
    Aland 10
    Boland 20 Aland
    Coland 15
    #
    

    输出样例:

    20
    

    题解

    主要难在输入上,

    写个快读, 特判 '#' 返回 -1

    写个map<string, int> 动态给新来的城市标号 / 旧城市直接 取编号

    然后dp状态 f[u][i] 以u为根至少获得i张票

    状态属性 最小值

    转移 f[u][i] = min(f[u][i - j] + f[son][j], f[u][i]);

    因为本身 f[son][y] 就在f[u][x]的集合之内, 所以我们要规定顺序

    强制在通过son转移的时候, 要把这个son先放在 f[u][x]集合之外

    然而按照边循环son转移正好可以满足

    这体现了dp阶段内当前状态的无后效性(大概)

    代码

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    using namespace std;
    typedef long long ll;
    
    const int maxn = 205;
    
    int n, m, a[maxn];
    int fa[maxn], si[maxn];
    int h[maxn], ne[maxn << 1], to[maxn << 1], tote;
    ll f[maxn][maxn];
    string s, t;
    map<string, int> st;
    
    int read()
    {
        char c = getchar();
        if (c == '#') return -1;
        while (c < '0' || c > '9') c = getchar();
        int ans = 0;
        while (c >= '0' && c <= '9')
        {
            ans = (ans << 3) + (ans << 1) + (c ^ '0');
            c = getchar();
        }
        return ans;
    }
    
    void unit(int x, int y)
    {
        fa[y] = x; ne[++tote] = h[x], h[x] = tote, to[tote] = y;
    }
    
    void dfs(int u)
    {
        f[u][0] = 0; si[u] = 1;
    
        for (int i = h[u]; i; i = ne[i])
        {
            dfs(to[i]);
            si[u] += si[to[i]];
        }
    
        for (int i = h[u]; i; i = ne[i])
            per (j, si[u], 0)
                per (k, min(si[to[i]], j), 1)
                    f[u][j] = min(f[u][j], f[u][j - k] + f[to[i]][k]);
    
        if (u) rep (j, 0, si[u]) f[u][j] = min(f[u][j], (ll)a[u]);
    }
    
    int main()
    {
        while (n = read(), n != -1)
        {
            m = read(); map<string, int>().swap(st);
            memset(f, 0x3f, sizeof f);
    
            rep(i, 0, n) fa[i] = i, f[i][0] = h[i] = 0;
            st[""] = 0; tote = 0;
    
            rep (i, 1, n)
            {
                cin >> s; int idxs;
                if (st.count(s)) idxs = st[s];
                else idxs = st.size(), st[s] = idxs;
    
                cin >> a[idxs];
    
                char c;
                while ((c = getchar()) != '
    ')
                {
                    cin >> t; int idxt;
                    if (st.count(t)) idxt = st[t];
                    else idxt = st.size(), st[t] = idxt;
                    unit(idxs, idxt);
                }
            }
    
            rep (i, 1, n) if (fa[i] == i) unit(0, i);
    
            dfs(0);
    
            cout << f[0][m] << '
    ';
    
        }
        return 0;
    }
    
  • 相关阅读:
    Codeforces Round #518 (Div. 1) Computer Game 倍增+矩阵快速幂
    BZOJ2756 [SCOI2012]奇怪的游戏 最大流
    Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)
    [AtCoder] NIKKEI Programming Contest 2019 (暂缺F)
    [AtCoder] Yahoo Programming Contest 2019
    Codeforces Round #538 (Div. 2) (CF1114)
    [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆
    [BZOJ2341][Shoi2011]双倍回文 manacher+std::set
    [BZOJ4278] [ONTAK2015]Tasowanie 贪心+后缀数组
    [BZOJ3451] Tyvj1953 Normal 点分治+FFT
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/12877883.html
Copyright © 2020-2023  润新知