题面
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;
}