http://poj.org/problem?id=3345
https://www.acwing.com/problem/content/326/
题意:
FIPA(国际国际计划协会联合会)近期将进行投票,以确定下一届IPWC(国际规划世界杯)的主办方。
钻石大陆的代表本内特希望通过以赠送钻石买通国家的方式,获得更多的投票。
当然,他并不需要买通所有的国家,因为小国家会跟随着他们附庸的大国进行投票。
换句话说,只要买通了一个大国,就等于获得了它和它统治下所有小国的投票。
例如,C在B的统治下,B在A的统治下,那么买通A就等于获得了三国的投票。
请注意,一个国家最多附庸于一个国家的统治下,附庸关系也不会构成环。
请你编写一个程序,帮助本内特求出在至少获得m个国家支持的情况下的最少花费是多少。
输入格式
输入包含多组测试数据。
第一行包含两个整数n和m,其中n表示参与投票的国家的总数,m表示获得的票数。
接下来n行,每行包含一个国家的信息,形式如下:
CountryName DiamondCount DCName DCName …
其中CountryName是一个长度不超过100的字符串,表示这个国家的名字,DiamondCount是一个整数,表示买通该国家需要的钻石数,DCName是一个字符串,表示直接附庸于该国家的一个国家的名字。
一个国家可能没有任何附庸国家。
当读入一行为#时,表示输入终止。
输出格式
每组数据输出一个结果,每个结果占一行。
数据范围
1<=m<=n<=200
经典的树上背包
dp[i][j]表示获得i国为根节点的j个国家支持最小的支出
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<string>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 207;
vector<int> V[maxn];
map<string, int> M;
int id, n, m;
int Val[maxn], flag[maxn], dp[maxn][maxn], siz[maxn];
void init() {
for (int i = 0; i <= n; i++)
V[i].clear();
M.clear();
id = 0;
memset(flag, 0, sizeof flag);
memset(siz, 0, sizeof siz);
memset(dp, INF, sizeof dp);
}
void tree_dp(int now) {
dp[now][0] = 0;
siz[now] = 1;
for (int i = 0; i < V[now].size(); i++) {
int &to = V[now][i];
tree_dp(to);
siz[now] += siz[to];
//for (int j = m; j >= 0; j--);
for (int j = siz[now]; j >= 0; j--) {
for (int k = j; k >= 0; k--) {
dp[now][j] = min(dp[now][j], dp[to][k] + dp[now][j - k]);
}
}
}
if (now) {
//dp[now][siz[now]] = Val[now]; !!!
for (int j = 0; j <= siz[now]; j++)
dp[now][j] = min(dp[now][j], Val[now]);
}
}
int main() {
stringstream ss;
string s;
while (getline(cin, s)) {
if (s[0] == '#')
break;
ss.clear();
ss << s;
ss >> n >> m;
init();
for (int i = 1; i <= n; i++) {
getline(cin, s);
ss.clear();
ss << s;
ss >> s;
if (!M.count(s))
M[s] = ++id;
ss >> Val[M[s]];
int fat = M[s];
while (ss >> s) {
if (!M.count(s))
M[s] = ++id;
V[fat].push_back(M[s]);
flag[M[s]] = 1;
}
}
for (int i = 1; i <= id; i++)
if (!flag[i])
V[0].push_back(i);
tree_dp(0);
cout << dp[0][m] << endl;
}
return 0;
}