DP练习1题解D

DP练习1题解D

先上题目描述

DP练习1题解D_第1张图片

样例输入
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
样例输出
3
8

emmm 因为POJ炸了 和讲台上面首A讲的好像有一点小区别(也可能我没听懂)
我不知道能不能过 所以。。
明天看下 先写在这里 不贴代码了
//第二天我来了 POJ还是没登上去T_T 那我就贴吧

首先是个图 n(n<=10000)个结点 n-1的边
合适用邻接表存储(不过此题可以用特殊的方式存储)见代码
也就是个树
是个树状DP
断掉一个点后 它之下的各个子树 和除了该点和它之下的点这棵树 构成了森林
要让每个树节点数小于等于n/2
断掉一个点要满足条件 也就是要除了该点和它之下的点总数小于等于n/2
并且它的子树中最大的树节点数小于等于n/2
我们可以从底部出发动归 传递上述两个状态 如果有点符合就输出

我的思路是用s数组存储相连的边数
d表存储连接情况 a数组存储它之下的点总数 和之下的最大的树节点数
拓扑排序结合DP
如果只有一条边和他相连 加入队列q
q不空就进行循环
取出一个只剩一个边的元素
判断是否符合 符合输出
相连的是它的父节点 向他传递状态
然后删除节点 更新父节点的表

以上

ps:GH当时刷不出来 没看 没做 明天写 要看英语了T_T要考四级了了了了了了了了了了

再:第二天起来真香了

#include
#include
#include
using namespace std;
int s[10001],d[10001];
int a[10001][3];
int main()
{
 int i,u,v,n,son,father;
 queue q;
 while(cin>>n)
 {
  memset(a,0,sizeof(a));
  memset(s,0,sizeof(s));
  memset(d,0,sizeof(d));
  for (i=1;i<=n-1;i++)
  {
   cin>>u>>v;
   s[u]++;
   s[v]++;
   d[u]=d[u]+v;
   d[v]=d[v]+u;
  }
  for (i=1;i<=n;i++)
   if (s[i]==1) q.push(i);
  while (!q.empty())
  {
   son=q.front();
   q.pop();
   father=d[son];
   if (a[son][1]+1>=n/2&&a[son][2]<=n/2) cout<a[father][2]) a[father][2]=a[son][1]+1;
    d[father]=d[father]-son;
    s[father]--;
    if (s[father]==1) q.push(father);
   }
  }
 }
 return 0;
}

也不知道对不对。。。等好了评测下吧

你可能感兴趣的:(周六练习)