• 【HDU4003】Find Metal Mineral


    题目大意:给定一棵 N 个节点的有根树,边有边权,在根结点处有 K 个人,这些人会遍历树上的所有边,求如何遍历才能使得所有人走过路径的边权和最小。

    题解:
    引理:对于一棵子树来说,若存在 M>0 个人最后停留在这棵子树内,则对于最优情况来说,来到过这棵子树的人也只能是 M 个,即:不会存在第 M+1 个人来到该子树,再回到其父节点的情况。
    证明:若存在第 M+1 个人来到了这棵子树,并走了一条路径 P,最后回到子树根节点的父节点。我们可以在 [1,M] 中任意选择一个人,先走与这个人相同的路径 P,再走这个人自己的路径,发现这样的代价会比第 M+1 个人要少,因为第 M+1 个人还要将来到和离开子树的代价计算在内,证毕。

    有了引理之后,就会消除树形dp状态设计因会有人返回的难点,直接dp即可。同样,我们还可以得到一个结论,即:若一棵子树中最后没有人停留,则一定是用了一个人遍历了这棵子树,并回到了父节点的结果。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+10;
    
    int n,s,m,dp[maxn][11];
    struct node{int nxt,to,w;}e[maxn<<1];
    int tot=1,head[maxn];
    inline void add_edge(int from,int to,int w){
    	e[++tot]=node{head[from],to,w},head[from]=tot;
    }
    
    void dfs(int u,int fa){
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to,w=e[i].w;
    		if(v==fa)continue;
    		dfs(v,u);
    		for(int j=m;j>=0;j--){
    			dp[u][j]+=dp[v][0]+2*w;
    			for(int k=1;k<=j;k++)
    				dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]+k*w);
    		}
    	}
    }
    void read_and_parse(){
    	for(int i=1;i<n;i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add_edge(x,y,z),add_edge(y,x,z);
    	}
    }
    void solve(){
    	dfs(s,0);
    	printf("%d
    ",dp[s][m]);
    }
    void init(){
    	memset(head,0,sizeof(head)),tot=1;
    	memset(dp,0,sizeof(dp));
    }
    int main(){
    	while(scanf("%d%d%d",&n,&s,&m)!=EOF){
    		init();
    		read_and_parse();
    		solve();
    	}
    	return 0;	
    } 
    
  • 相关阅读:
    lookup:ID列
    分享几篇文章
    怎样无限制使用smartgit ?
    C++ Win32控制台应用程序捕捉关闭事件
    mt4 在K线上 放文字
    变色指标
    用windows 打包 证书
    监管fca asic nfa 啥啥啥
    sublime 3 build 3126 code ,压缩包在我的360企业云盘里,搜sublime
    个人作业收官——软件工程实践总结
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10927872.html
Copyright © 2020-2023  润新知