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