码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-05-12 18:50:54      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:swap   ret   pac   turn   钻石   +=   接下来   name   没有   

题面

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()) != ‘\n‘)
            {
                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] << ‘\n‘;

    }
    return 0;
}

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

标签:swap   ret   pac   turn   钻石   +=   接下来   name   没有   

原文地址:https://www.cnblogs.com/2aptx4869/p/12877883.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!