hdu4003 Find Metal Mineral(树形dp)
src: http://acm.hdu.edu.cn/showproblem.php?pid=4003
思路:dp[u][k]表示遍历完u的子树后,有k个机器人没有回到u。 对于结点u,如果机器人回来的话,派几个都是一样,所以考虑不回来的数量,而k决定了不回来个数的上限,另外 ,机器人最终都会停在叶节点!!!
ac代码:
#include <iostream> #include<stdio.h> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack> #include<time.h> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define Max(a,b) a=max(a,b) #define Min(a,b) a=min(a,b) const int inf=99999999; int n,s,k,dp[10001][12],Enum=0,head[10001]; struct node { int to,ne,v; }edge[20010]; void init() { Enum=0; memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); }; void add_edge(int a,int b,int v) { edge[Enum].to=b; edge[Enum].v=v; edge[Enum].ne=head[a]; head[a]=Enum++; } void dfs(int u,int fa) { for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; if(v==fa)continue; dfs(v,u); for(int m=k;m>=0;m--){//分组背包 dp[u][m]+=(dp[v][0]+2*edge[i].v); for(int j=1;j<=m;j++){//dp[u][m-j]指的是j个机器人用于子树v,而m-j用于除子树v外的其他子树 Min(dp[u][m],dp[u][m-j]+dp[v][j]+j*edge[i].v);//注意是j* } //这里dp[u][j-k]已经是上个阶段的了,就是只遍历了该父节点的前面的子树的情况!!! } } } int main() { ios::sync_with_stdio(false); while(cin>>n>>s>>k){ init(); int a,b,c; for(int i=1;i<n;i++){ //cin>>a>>b>>c; scanf("%d %d %d",&a,&b,&c); add_edge(a,b,c);add_edge(b,a,c); } dfs(s,-1); cout<<dp[s][k]<<endl; } return 0; }

浙公网安备 33010602011771号