POJ 3345 Bribing FIPA 树上背包

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值