zoukankan      html  css  js  c++  java
  • HDU 5758 Explorer Bo 2016多校第三场1007 树上DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5758
    题意:给你一颗树,树上有n个节点,有n-1条路,让你每条路至少走一遍,在走的过程中,你可以从一节点跳到其他任意节点,但不能重复走刚走过的路(也就是如果从a到b,那么此时不能立即从b走到a),让你找出在跳的次数最少的情况下走的最少步数。
    题解:这是一个最小链覆盖问题。显然知道当走到叶子结点(也就是该节点没有子节点)时,这种情况是必须跳的。此时就应该跳到没有走到过的节点,但有由于需要考虑跳的次数要最少,那么我们知道在走如果以叶子结点为终点,此时跳的次数一定会增加(除非这是最后一次)。所以跳的时候一般从一个叶子结点跳到另外一个叶子结点。那么我们再来考虑走的步数最小化问题。根据以上分析,显然可以知道,为了首先保证跳的次数最少,那么每一次走一定是从一个叶子结点走到另外一个叶子结点,然后下一次又从另外一个没到过的叶子结点开始。因此,我们可以知道,对于一个节点的叶子结点来说,叶子结点个数的奇偶性决定了跳的次数。
    点。
    如图:
    叶子结点为奇数时,首先从外面经过a节点后会走到b、c、d任意一个节点,那么剩下两个节点就可以从某一个开始走到另一个节点,比如从外面进来走到了b,那么下一步我们就可以从c走到d。
    叶子结点为偶数时,同样进来先到某一个节点,那么剩下了奇数个叶子结点,肯定会多出一个向外走出去的(如果其他节点的叶子结点还没走完)。

    根据以上分析,我们确定了跳的情况,那么就可以直接考虑一个暴力的树上dp求最小步数即可。dp[i]表示在深搜中i节点走到上一个节点的总步数(包括i节点子节点的步数)。由于要考虑叶子结点的两两搭配,那么我们可以增加一个维度来记录。详细看代码。
    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int inf = 0x3f3f3f3f;
    const int maxn=1e5+50;
    int t;
    int n;
    int dp[maxn][2];
    //dp[i][0]表示i节点子节点各自要走的步数
    //dp[i][1]表示i节点叶子结点两两搭配后的步数
    int eadg[maxn],son[maxn];
    vector<int>v[maxn];
    
    void dfs(int x,int f)
    {
    	dp[x][0]=0;
    	dp[x][1]=inf;
    	int chd=0;
    	//cout<<":"<<x<<":"<<endl;
    	for(int i=0;i<v[x].size();i++)//先考虑x节点子节点各自走的步数
    	{
    		if(v[x][i]==f)
    			continue;
    		dfs(v[x][i],x);
    		chd++;
    		son[x]+=son[v[x][i]];
    		int d=(son[v[x][i]]&1?1:2);//考虑x节点走到上一个节点步数,奇数+1,偶数+2
    		dp[x][0]+=dp[v[x][i]][0]+d;
    		//cout<<v[x][i]<<":"<<son[x]<<" "<<dp[x]<<endl;
    	}
    	for(int i=0;i<v[x].size();i++)//考虑x节点的叶子节点两两搭配之后的步数
    	{
    		if(v[x][i]==f)
    			continue;
    		if(son[v[x][i]]==1)
    			dp[x][1]=min(dp[x][0],dp[x][1]);
    		int d=(son[v[x][i]]&1?1:-1);
    		dp[x][1]=min(dp[x][1],dp[x][0]-dp[v[x][i]][0]+dp[v[x][i]][1]+d);
    	}
    	if(!chd) son[x]=1;
    }
    
    int main()
    {
    	//freopen("in.txt","r",stdin);
    	cin>>t;
    	while(t--)
    	{
    		memset(son,0,sizeof(son));
    		memset(eadg,0,sizeof(eadg));
    		scanf("%d",&n);
    		for(int i=0;i<=n;i++)
    			v[i].clear();
    		int a,b;
    		for(int i=0;i<n-1;i++)
    		{
    			scanf("%d%d",&a,&b);
    			v[a].push_back(b);
    			v[b].push_back(a);
    			eadg[a]++;
    			eadg[b]++;
    		}
    		if(n==2)
    		{
    			puts("1");
    			continue;
    		}
    		int root;
    		int cnt=0;
    		for(int i=1;i<=n;i++)
    			if(eadg[i]!=1)
    				root=i;
    			else
    				cnt++;
    		dfs(root,0);
    		printf("%d\n",dp[root][cnt&1]);
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    modals-methods 模态框 使用说明文档
    jquery validate form 异步提交
    log在线生成器 html中如何设置浏览器中标题前的logo
    解决django关于图片无法显示的问题
    Git远程操作
    Git基本操作
    Git思维导图
    连接GitHub的方法
    Git的三种区域
    Gentoo(贱兔)Linux安装笔记
  • 原文地址:https://www.cnblogs.com/zhuyutian/p/5798910.html
Copyright © 2011-2022 走看看