HDU 5758 Explorer Bo

题目:Explorer Bo

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5758

题意:给一棵树,树边的长度都是1,要求遍历他的所有边至少一次,起始点可以任意选,不能回头(但一条边可以遍历多次),可以传送到任意一点,在完成目的的基础上,传送次数越少越好(第一优先级),走过的路越短越好(第二优先级),输出走过的路的总长度。

思路:

  这道题的难度不算很大,思路很容易就能想出来,但实现细节有点麻烦,比赛时候没去看有点可惜了(容我吹会B,实际上做这题花了一整个下午,WA到死啊,所以末尾附上一些我错过的测试数据)。

  可以想象,传送次数是第一优先级,所以只有当遍历到叶子结点的时候才会使用传送,令 x = 叶子结点数,所以传送次数为:(x+1)/2,而每一次遍历都是从一个叶子结点到另一个叶子结点。

  

  现在对每一条边进行初步计数,假设他下面有奇数个叶子结点,那么这条边要遍历一次,上图的A边初步计数就是遍历1次,因为他下面三个叶子结点可以自己搭配,剩下一个从A边通往外面和别人搭配。图2中A边初步预计要遍历2次,因为下面四个叶子结点不能全部自己搭配,如果这样,那红点就变成了一个新的叶子结点,可能会增加传送次数。所以只能有一对自己搭配,其他两个都要经过A边。

  上面的初步计数可以通过深入优先搜索进行,如果树的叶子结点数是偶数个,那么答案已经出来了,现在要处理叶子结点奇数的情况。(处理原因就是奇数的情况下,叶子结点可以容许再出现一个,就像图二中红点一样)。

  

  现在看图3,A边原本计数是2,但如果总的叶子结点数是奇数,那么我们可以让红点下面的四个点自己搭配,然后红点作为一个新的叶子结点再和别人配对,这样A边的计数就变成了1,原本B边的计数是1(奇数个叶子结点),现在就变成了2,因为如果红点和蓝点配对,那黑点又变成了一个新的叶子结点(但事实上只容许多出一个),所以B边得经过两次。

  所以,我们就要从根结点开始深搜,每次都尝试对某个子树进行改变,将边1变成2,2变成1,然后每次都取最优(也就是子树的边计数减少最多的)。有了思路,代码实现就比较简单了,也可以参考我下面的AC代码。

AC代码:

 

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<vector>
  4 using namespace std;
  5 struct ENode
  6 {
  7   int ad;
  8   int num;
  9 };
 10 vector<ENode> e[100010];
 11 bool u[100010];
 12 int sum=0;
 13 int dfs(int rt,int fa,int fi)
 14 {
 15   u[rt]=1;
 16   int s=0;
 17   for(int i=0;i<e[rt].size();i++)
 18   {
 19     if(u[e[rt][i].ad]==0)
 20     {
 21       e[rt][i].num=dfs(e[rt][i].ad,rt,i);
 22       s+=e[rt][i].num;
 23     }
 24   }
 25   sum+=s;
 26   if(s==0) s=1;
 27   if(s&1) s=1;
 28   else s=2;
 29   return s;
 30 }
 31 int dfs2(int rt)
 32 {
 33   int mm=0;
 34   for(int i=0;i<e[rt].size();i++)
 35   {
 36     if(e[rt][i].num==1)
 37     {
 38       int tmp=dfs2(e[rt][i].ad);
 39       if(tmp-1>mm) mm=tmp-1;
 40     }
 41     else if(e[rt][i].num==2)
 42     {
 43       int tmp=dfs2(e[rt][i].ad);
 44       if(tmp+1>mm) mm=tmp+1;
 45     }
 46   }
 47   return mm;
 48 }
 49 int du[100010];
 50 int qiuCha(int n)
 51 {
 52   int co=0;
 53   for(int i=1;i<=n;i++)
 54   {
 55     if(du[i]==1) co++;
 56   }
 57   if(co%2==0) return 0;
 58   return dfs2(1);
 59 }
 60 int main()
 61 {
 62   int t,n,x,y;
 63   scanf("%d",&t);
 64   while(t--)
 65   {
 66     scanf("%d",&n);
 67     for(int i=1;i<=n;i++) e[i].clear();
 68     memset(du,0,sizeof(du));
 69     for(int i=0;i<n-1;i++)
 70     {
 71       scanf("%d%d",&x,&y);
 72       du[x]++;
 73       du[y]++;
 74       ENode tmp;
 75       tmp.ad=y;
 76       tmp.num=0;
 77       e[x].push_back(tmp);
 78       tmp.ad=x;
 79       e[y].push_back(tmp);
 80     }
 81     memset(u,0,sizeof(u));
 82     ENode tmp;
 83     tmp.ad=1;
 84     sum=0;
 85     dfs(1,0,0);
 86     int cha=qiuCha(n);
 87     printf("%d\n",sum-cha);
 88   }
 89   return 0;
 90 }
 91 
 92 /*
 93 易错数据:
 94 6666
 95 16
 96 9 2
 97 12 2
 98 1 12
 99 9 7
100 8 4
101 4 9
102 10 11
103 11 12
104 16 10
105 6 8
106 13 1
107 10 3
108 14 11
109 6 15
110 5 6
111 9
112 1 2
113 1 3
114 3 4
115 3 5
116 5 6
117 5 7
118 7 8
119 7 9
120 10
121 1 2
122 1 3
123 1 4
124 1 6
125 6 7
126 7 8
127 7 9
128 7 10
129 7 5
130 12
131 1 2
132 1 3
133 1 4
134 1 5
135 2 7
136 2 6
137 6 8
138 8 9
139 8 10
140 7 11
141 7 12
142 13
143 1 2
144 1 3
145 3 4
146 3 5
147 5 6
148 5 7
149 7 8
150 8 9
151 9 10
152 10 11
153 11 12
154 11 13
155 6
156 1 2
157 2 3
158 2 4
159 2 5
160 2 6
161 
162 答案是:
163 18
164 9
165 9
166 12
167 13
168 5
169 */

 

posted @ 2016-07-27 19:06  hchlqlz  阅读(668)  评论(1编辑  收藏  举报