pku3345 Bribing FIPA

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

你可能感兴趣的:(bing)