/**//* Note that no country is under domination of more than one country, and the domination relationship makes no cycle. 给出一棵树,每个点有代价,选了父亲就能选中所有儿子,求最小的代价选中至少m个以上的点 直接tree dp +背包 但是注意不要重复算!选了父亲就相当于所有儿子都选了,就不能在这个基础上枚举儿子来更新! */ #include<cstdio> #include<cstring> #include<string> #include<vector> #include <sstream> #include<algorithm> #include<map> using namespace std;
const int MAXN=210; const int INF=1000000000;
vector<int>G[MAXN]; int dp[MAXN][MAXN]; int cost[MAXN],in[MAXN]; bool vi[MAXN]; int n,m;
int dfs(int u){ vi[u]=1; int num=1; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(vi[v])continue; num+=dfs(v); } for(int j=0;j<=n;j++)dp[u][j]=INF; dp[u][0]=0; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; for(int j=n;j;j--){ for(int k=1;j-k>=0;k++) if(dp[u][j]>dp[u][j-k]+dp[v][k]) dp[u][j]=dp[u][j-k]+dp[v][k]; } } //不要放在上面,因为num包括了所有儿子节点,然后还更新的话,就是重复了! if(dp[u][num]>cost[u])dp[u][num]=cost[u]; return num; } int main(){ char str[1000]; while(gets(str)){ if(str[0]=='#')break; sscanf(str,"%d%d",&n,&m); for(int i=0;i<=n;i++)G[i].clear(); map<string,int>Map; memset(in,0,sizeof(in)); int ID=0; for(int i=1;i<=n;i++){ scanf("%s",str); if(Map.find(str)==Map.end())Map[str]=++ID; int u=Map[str]; scanf("%d",&cost[u]); //while(getchar()==' '){//因为只有空格! // scanf("%s",str); // if(Map.find(str)==Map.end())Map[str]=++ID; // G[u].push_back(Map[str]); // in[Map[str]]++; //} gets(str); stringstream ss(str); string name; while(ss>>name){ if(Map.find(name)==Map.end())Map[name]=++ID; G[u].push_back(Map[name]); in[Map[name]]++; } } cost[0]=INF; for(int i=1;i<=n;i++){ if(in[i])continue; G[0].push_back(i); } memset(vi,0,sizeof(vi)); dfs(0); int ans=INF; for(int j=m;j<=n;j++) if(dp[0][j]!=-1&&dp[0][j]<ans)ans=dp[0][j]; printf("%d\n",ans); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|