题目大意:美丽城镇想用钻石贿赂参与投票的国家给它投票,当贿赂一个国家时,还包含了这个国家管辖的国家,问最少用多少钻石能让美丽城镇赢得票选
输入:参与投票国家数量n 美丽城镇赢得票选所需票数m(1<=n<=200,0<=m<=n)
国家名字 贿赂它所需的钻石数量 它管辖的国家名字
#//代表结束输入
输出:最少钻石数量
分析:树形动态规划
由于输入可能是个森林,所以要设置一个总根
num[u]是以u为根的子树有多少个结点
状态:dp[u][j]为以u为根的子树(国家)中选取j个结点(国家)的最小代价
状态转移方程:dp[u][j]=min{dp[u][j],dp[v][k]+dp[u][j-k]},(k<=j && k<=num[v])
代码:转载自http://blog.csdn.net/ascii991/article/details/7448072(有改动,添加了一些注释)
- #include <cstdio>
- #include <cstring>
- #include <string>
- #include <vector>
- #include <map>
- using namespace std;
- const int maxn=205,oo=99999999;
- vector<int> g[maxn];
- int dp[maxn][maxn],v[maxn],num[maxn];
- bool fa[maxn];
- int n,m,id;
- int dfs(int x)
- {
- num[x]=1; //记录以x为根的子树共有多少个结点
- int i,j,k,y;
- for (k=0;k<g[x].size();k++)
- {
- y=g[x][k];
- num[x]+=dfs(y);
- }
- for (k=0;k<=n;k++) dp[x][k]=INF;
- dp[x][0]=0;
- dp[x][num[x]]=v[x];
- for (k=0;k<g[x].size();k++)
- {
- y=g[x][k];
- for (i=num[x];i>=0;i--) //对于x为根来说,可以选择它子树中的num[x]~0个结点
- for (j=0;j<=i && j<=num[y];j++)//减少以x为根选择的结点,增加以y为根选择的结点 ,看是否能让代价减小
- if (dp[x][i-j]+dp[y][j]<dp[x][i])
- dp[x][i]=dp[x][i-j]+dp[y][j];
- }
- return num[x];
- }
- int main()
- {
- freopen("pin.txt","r",stdin);
- freopen("pou.txt","w",stdout);
- char str[1000];
- int i,j,ans,now;
- while (gets(str))
- {
- if (str[0]=='#') break;
- sscanf(str,"%d%d",&n,&m);
- map<string,int> wmap;
- for (i=0;i<=n;i++)
- g[i].clear();
- memset(fa,0,sizeof(fa));
- id=0;
- for (i=1;i<=n;i++)
- {
- scanf("%s",str);
- if (wmap.find(str)==wmap.end()) //如果str不在map中
- wmap[str]=++id;
- now=wmap[str]; //当前国家的id编号
- scanf("%d",&v[now]); //选了now国家的代价
- while (getchar()!='\n')
- {
- scanf("%s",str);
- if (wmap.find(str)==wmap.end())
- wmap[str]=++id;
- g[now].push_back(wmap[str]); //push受now国家管辖的国家id编号
- fa[wmap[str]]=true; //表明该国家是被管辖的,即有父亲结点
- }
- }
- v[0]=INF; //输入的可能是个森林,所以要建立一个总根
- for (i=1;i<=n;i++)
- {
- if (fa[i]) continue;
- g[0].push_back(i); 将那些没有父亲结点的国家与总根相连
- }
- dfs(0);
- ans=dp[0][m];
- for (i=m;i<=n;i++) //要选举成功,必须有m或m以上各国家投它
- if (dp[0][i]<ans) ans=dp[0][i];
- printf("%d\n",ans);
- }
- return 0;
- }