题意:
从一棵有n个节点的树中,每个节点均有一个权值。
当你选择了一个节点,则以该节点为根的所有的节点都属于你的。
找出m个点使得所花费的费用最少。
思路:
这题主要麻烦在字符串处理= =。不过也好,对atoi函数,substr函数又熟悉了。
由于没有根结点,因此要自己建立一个根节点。
状态定义:
dp[i][j]:以i节点为根的树中,获得j个节点所需要的最小费用。
转移方程:
dp[i][j] = min{dp[i][p] + dp[son][j-p] };
code:(写的有点挫)
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 205;
const int INF = 0x3f3f3f3f;
int n, m;
int dp[MAXN][MAXN];
int son[MAXN];
map <string, int> mp;
vector <int> G[MAXN];
int val[MAXN];
bool vis[MAXN];
int getSonNum(int u, int par)
{
int num = 1;
for(int i = 0;i < G[u].size(); i++)
{
int v = G[u][i];
if(v == par) continue;
num += getSonNum(v, u);
}
return son[u] = num;
}
void dfs(int u, int par)
{
dp[u][0] = 0;
//cout<<"u = "<<u<<" val = "<<val[u]<<endl;
for(int i = 1;i <= son[u]; i++)
dp[u][i] = val[u];
for(int i = 0;i < G[u].size(); i++)
{
int v = G[u][i];
if(v == par) continue;
dfs(v, u);
for(int t = min(m, son[u]); t >= 0; t--)
{
int tmp = dp[u][t];
for(int p = 0;p <= t; p++)
tmp = min(tmp, dp[u][p] + dp[v][t-p]);
dp[u][t] = tmp;
}
}
}
void solve()
{
memset(dp, INF, sizeof(dp));
{
int sum = 0;
for(int i = 0;i < G[1].size(); i++)
{
int v = G[1][i];
sum += val[v];
}
val[1] = sum;
}
getSonNum(1, -1);
/**/
son[1]--;
dfs(1, -1);
//cout<<"dp[3][3] = "<<dp[3][3]<<endl;
cout<<dp[1][m]<<endl;
}
void init()
{
memset(dp, INF, sizeof(dp));
memset(vis, false, sizeof(vis));
mp.clear();
for(int i = 1;i <= n+1; i++)
G[i].clear();
}
int main()
{
ios::sync_with_stdio(false);
string nm;
//freopen("in.txt", "r", stdin);
while(getline(cin, nm))
{
if(nm == "#") break;
init();
int mid;
for(int i = 0;i < nm.length(); i++)
if(nm[i] == ' ')
{
mid = i;
break;
}
n = atoi(nm.substr(0, mid).c_str());
m = atoi(nm.substr(mid+1).c_str());
//cout<<"n = "<<n<<" m = "<<m<<endl;
int cot = 2; //the value record the number of node;
for(int i = 0;i < n; i++)
{
getline(cin, nm);
int last = 0, mid;
bool token = false;
int u;
for(int j = 0;j < nm.length(); j++)
{
if(nm[j] != ' ' && j != nm.length()-1) continue;
mid = j;
if(j == nm.length() - 1)
mid++;
if(nm[last] >= '0' && nm[last] <= '9')
val[u] = atoi(nm.substr(last, mid-last).c_str());
else
{
string tmp = nm.substr(last, mid - last);
//cout<<"str = "<<tmp<<endl;
//find tmp, whether is exist
int rank;
if(mp.find(tmp) != mp.end())
rank = mp[tmp];
else
{
rank = cot;
mp[tmp] = cot++;
}
//build graph;
if(token == false)
{
u = rank;
token = true;
}
else
{
G[u].push_back(rank);
vis[rank] = true; // while true, means node 1 shouldn't connect it;
}
}
last = mid+1;
}
}
//connect by 1;
for(int i = 2;i <= n+1; i++)
{
if(vis[i]) continue;
G[1].push_back(i);
}
/*
cout<<"test"<<endl;
for(int i = 1;i <= n+1; i++)
{
cout<<"u = "<<i<<endl;
for(int j = 0;j < G[i].size(); j++)
{
cout<<G[i][j]<<" ";
}
cout<<endl;
}
*/
solve();
}
return 0;
}