d[u][j]表示从以u为根的子树中获得j张选票时的最小花费
转移方程为:d[u][j] = min(sigema(d[vi][ji]));设u有n个儿子v1...vn,这里表示选取所有j1+...+jn=j的组合中有最小花费的组合
方程虽然暴力,但是很好懂很好实现
#include
<
iostream
>
#include < vector >
#include < map >
#include < string >
using namespace std;
#define MAXN 210
#define INF 0x7f7f7f7f
int d[MAXN][MAXN], n, m, c[MAXN], cnt, nodnum[MAXN];
int indeg[MAXN];
vector < int > son[MAXN];
map < string , int > mp;
void init(){
int i;
cnt = 1 ;
memset(d, 0x7f , sizeof (d));
mp.clear();
for (i = 0 ; i <= n; i ++ )
son[i].clear();
memset(indeg, 0 , sizeof (indeg));
}
int input( string name){
map < string , int > ::iterator it = mp.find(name);
if (it != mp.end())
return it -> second;
mp[name] = cnt ++ ;
return cnt - 1 ;
}
int calnum( int u){
nodnum[u] = 1 ;
int i, sz;
sz = son[u].size();
for (i = 0 ; i < sz; i ++ )
nodnum[u] += calnum(son[u][i]);
return nodnum[u];
}
void dfs( int u){
int i, j, k, sz, v;
sz = son[u].size();
for (i = 0 ; i < sz; i ++ )
dfs(son[u][i]);
for (i = 0 ; i < sz; i ++ ){
v = son[u][i];
for (j = nodnum[u] - 1 ; j >= 0 ; j -- ){
if (d[u][j] != INF){
for (k = 1 ; k <= nodnum[v]; k ++ ){
d[u][j + k] = min(d[u][j + k], d[u][j] + d[v][k]);
}
}
}
}
d[u][nodnum[u]] = c[u];
}
int main(){
int i, j, k, u, v, num, sum, mn;
char name[ 200 ];
while (scanf( " %d " , & n) != 0 ){
init();
scanf( " %d " , & m);
getchar();
for (i = 0 ; i < n; i ++ ){
scanf( " %s " , & name);
u = input(name);
scanf( " %d " , & c[u]);
while (getchar() == ' ' ){
scanf( " %s " , & name);
v = input(name);
son[u].push_back(v);
indeg[v] ++ ;
}
}
sum = 0 ;
cnt = 1 ;
d[ 0 ][ 0 ] = 0 ;
for (i = 1 ; i <= n; i ++ ){
if (indeg[i] == 0 ){
son[ 0 ].push_back(i);
sum += c[i];
}
d[i][ 0 ] = 0 ;
}
c[ 0 ] = sum;
calnum( 0 );
nodnum[ 0 ] -- ;
dfs( 0 );
int mn = INF;
for (i = m; i <= n; i ++ )
if (d[ 0 ][i] < mn)
mn = d[ 0 ][i];
printf( " %d\n " , mn);
}
return 0 ;
}
#include < vector >
#include < map >
#include < string >
using namespace std;
#define MAXN 210
#define INF 0x7f7f7f7f
int d[MAXN][MAXN], n, m, c[MAXN], cnt, nodnum[MAXN];
int indeg[MAXN];
vector < int > son[MAXN];
map < string , int > mp;
void init(){
int i;
cnt = 1 ;
memset(d, 0x7f , sizeof (d));
mp.clear();
for (i = 0 ; i <= n; i ++ )
son[i].clear();
memset(indeg, 0 , sizeof (indeg));
}
int input( string name){
map < string , int > ::iterator it = mp.find(name);
if (it != mp.end())
return it -> second;
mp[name] = cnt ++ ;
return cnt - 1 ;
}
int calnum( int u){
nodnum[u] = 1 ;
int i, sz;
sz = son[u].size();
for (i = 0 ; i < sz; i ++ )
nodnum[u] += calnum(son[u][i]);
return nodnum[u];
}
void dfs( int u){
int i, j, k, sz, v;
sz = son[u].size();
for (i = 0 ; i < sz; i ++ )
dfs(son[u][i]);
for (i = 0 ; i < sz; i ++ ){
v = son[u][i];
for (j = nodnum[u] - 1 ; j >= 0 ; j -- ){
if (d[u][j] != INF){
for (k = 1 ; k <= nodnum[v]; k ++ ){
d[u][j + k] = min(d[u][j + k], d[u][j] + d[v][k]);
}
}
}
}
d[u][nodnum[u]] = c[u];
}
int main(){
int i, j, k, u, v, num, sum, mn;
char name[ 200 ];
while (scanf( " %d " , & n) != 0 ){
init();
scanf( " %d " , & m);
getchar();
for (i = 0 ; i < n; i ++ ){
scanf( " %s " , & name);
u = input(name);
scanf( " %d " , & c[u]);
while (getchar() == ' ' ){
scanf( " %s " , & name);
v = input(name);
son[u].push_back(v);
indeg[v] ++ ;
}
}
sum = 0 ;
cnt = 1 ;
d[ 0 ][ 0 ] = 0 ;
for (i = 1 ; i <= n; i ++ ){
if (indeg[i] == 0 ){
son[ 0 ].push_back(i);
sum += c[i];
}
d[i][ 0 ] = 0 ;
}
c[ 0 ] = sum;
calnum( 0 );
nodnum[ 0 ] -- ;
dfs( 0 );
int mn = INF;
for (i = m; i <= n; i ++ )
if (d[ 0 ][i] < mn)
mn = d[ 0 ][i];
printf( " %d\n " , mn);
}
return 0 ;
}