您的位置:首页 > 其它

树形DP______Bribing FIPA( POJ 3345 )

2016-08-20 14:49 330 查看
Description

There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (International Programming World Cup). Benjamin Bennett, the delegation of Diamondland to FIPA, is trying to seek other
delegation's support for a vote in favor of hosting IWPC in Diamondland. Ben is trying to buy the votes by diamond gifts. He has figured out the voting price of each and every country. However, he knows that there is no need to diamond-bribe every country,
since there are small poor countries that take vote orders from their respected superpowers. So, if you bribe a country, you have gained the vote of any other country under its domination (both directly and via other countries domination). For example, if
C is under domination of B, and B is under domination of A, one may get the vote of all three countries just by bribing A. Note that no country is under domination of more than one country, and the domination relationship makes no cycle. You are to help him,
against a big diamond, by writing a program to find out the minimum number of diamonds needed such that at least m countries vote in favor of Diamondland. Since Diamondland is a candidate, it stands out of the voting process.

Input

The input consists of multiple test cases. Each test case starts with a line containing two integers n (1 ≤ n ≤ 200) and m (0 ≤ m ≤ n) which are the number of countries participating in the voting process, and
the number of votes Diamondland needs. The next n lines, each describing one country, are of the following form:

CountryName DiamondCount DCName1 DCName1 ...

CountryName, the name of the country, is a string of at least one and at most 100 letters and DiamondCount is a positive integer which is the number of diamonds needed to get the vote of that country and all of the countries that their
names come in the list DCName1 DCName1 ... which means they are under direct domination of that country. Note that it is possible that some countries do not have any other country under domination. The end of the input
is marked by a single line containing a single # character.

Output

For each test case, write a single line containing a number showing the minimum number of diamonds needed to gain the vote of at least m countries.

Sample Input
3 2
Aland 10
Boland 20 Aland
Coland 15
#

Sample Output
20


题意:

有N个国家,每个国家可能有附属国,但是保证一个国家最多会被一个国家附属。给出每个国家的价格,现在需要至少买M个国家,当然,如果买了一个国家就相当于买了该国家和及其所有附属国。求最少花费。

分析:

显然这个是一个树的模型。这就是一个树形DP.

令dp[ i ] [ j ]  是表示在以 i 为根的子树中刚好购买 j 个国家的最小花费。

则:状态转移方程式为

dp[ now ] [ j ] = dp[ next ] [ k ] + dp[ now ] [ j - k ] .

next 是now 节点的儿子,  0 <= j <= num[ now ] , 0 <= k <= j && 0 <= k <= num[ next ] . num[ x ] 表示以x为根的子树所有节点数。

注意:

因为有些国家可能没有被附属。所以可能是森林结构,这个时候引入一个编号0的国家,附属这些根节点。然后这0这个国家的价格为INF。

分析:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
int m,n;
int v[220];
int dp[220][220];
int num[220];
int fa[220];
vector<int>edge[220];
map<string,int>mpt;

int dfs(int index)
{
num[index] = 1;
for(int i = 0 ; i <= n ; i ++) dp[index][i] = inf;
for(int i = 0 ; i < edge[index].size() ; i ++)
num[index] += dfs(edge[index][i]);
dp[index][0] = 0;
dp[index][num[index]] = v[index];
for(int i = 0 ; i < edge[index].size() ; i ++)
{
int next = edge[index][i];
for(int j = num[index] ; j >= 0 ; j --)
{
for(int k = 0 ; k <= j && k <= num[next] ; k ++)
{
if(dp[index][j] > dp[index][j-k] + dp[next][k])
dp[index][j] = dp[index][j-k]+dp[next][k];
}
}
}
return num[index];
}
int main()
{
char str[30];
while(gets(str))
{
if(str[0] == '#') break;
sscanf(str,"%d%d",&n,&m);
for(int i = 0 ; i <= n ; i ++)
edge[i].clear();
mpt.clear();
memset(fa,0,sizeof(fa));
int tot = 0;
for(int i = 1 ; i <= n ; i ++)
{
scanf("%s",str);
if(mpt.find(str) == mpt.end())
mpt[str] = ++tot;
int now = mpt[str];
scanf("%d",&v[now]);
while(getchar()!='\n')
{
scanf("%s",str);
if(mpt.find(str) == mpt.end())
mpt[str] = ++tot;
edge[now].push_back(mpt[str]);
fa[mpt[str]] = 1;
}
}
for(int i = 1 ; i <= n ; i ++)
if(!fa[i]) edge[0].push_back(i);
v[0] = inf;
dfs(0);
int ans = inf;
for(int i = m ; i <=n ; i ++)
if(ans > dp[0][i]) ans = dp[0][i];
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树形DP POJ 3345