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
<stringint> mp;

void init(){
    
int i;
    cnt 
= 1;
    memset(d, 
0x7fsizeof(d));
    mp.clear();
    
for (i = 0; i <= n; i++)
        son[i].clear();
    memset(indeg, 
0sizeof(indeg));
}

int input(string name){
    map
<stringint>::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;
}
posted @ 2009-03-28 22:48  Beetlebum  阅读(377)  评论(0编辑  收藏  举报