bzoj4871 [Heoi2017]摧毁“树状图”
刷完了去年的省选题,发现自己dp已经凉凉了。
虽然暴力可以拿到80分的好成绩,但是正解的dp状态和转移还是没能想到,是时候补一波dp了
这道题我们肯定是要树形dp,存的肯定就是子树某种状态的最多的联通块数,那么我们发现有这么几个因素会影响转移
1.子树的根是否被删掉
2.是否有一条链可以从子树中伸出去,即根连的链数是不是奇数
3.子树中共出现了几条路径
那么f[i][0/1(n点删不删)][0/1(能否向上扩展)][0/1/2(子树中共有几条路径)]就是我们的数组定义
转移时我是直接让新的子树和已有的子树信息进行合并,也需要额外记录两个信息,即当前共有几棵子树和当前子树中只有1条路径时的删去根结点时的信息。
看起来状态定义十分麻烦,但是实际只有6个状态是有用的,手动转移,理解了就比较简单。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #define N 100500 7 using namespace std; 8 int e=1,head[N]; 9 struct edge{ 10 int v,next; 11 }ed[N<<1]; 12 inline void add(int u,int v){ 13 ed[e].v=v; 14 ed[e].next=head[u]; 15 head[u]=e++; 16 } 17 int T,opt,n,ans; 18 int f[N][2][2][3];//f[i][0/1(n点删不删)][0/1(能否向上扩展)][0/1/2(子树中共有几条路径)] 19 inline void gmax(int &x,int y){x=x>y?x:y;} 20 inline int Max(int x,int y){return x>y?x:y;} 21 void dfs(int x,int fa){ 22 int son=0,t=0; 23 for(int i=head[x];i;i=ed[i].next){ 24 int v=ed[i].v; 25 if(v==fa)continue; 26 dfs(v,x); 27 int f1,f2,f3,f4,f5,f6; 28 f1=f[x][0][0][1]; 29 f2=f[x][0][0][2]; 30 f3=f[x][1][1][1]+1; 31 f4=f[x][1][0][1]+1; 32 f5=f[x][1][1][2]+1; 33 f6=f[x][1][0][2]+1; 34 gmax(f1,f[v][0][0][1]); 35 gmax(f1,f[v][1][0][1]+1); 36 gmax(f1,f[v][1][1][1]+1); 37 38 gmax(f2,f[v][0][0][2]); 39 gmax(f2,f[v][1][0][2]+1); 40 gmax(f2,f[v][1][1][2]+1); 41 gmax(f2,f[x][0][0][1]+f[v][0][0][1]-1); 42 gmax(f2,f[x][0][0][1]+f[v][1][0][1]); 43 gmax(f2,f[x][0][0][1]+f[v][1][1][1]); 44 45 gmax(f3,f[v][1][1][1]+son); 46 gmax(f4,f[x][1][1][1]+f[v][1][1][1]); 47 48 gmax(f5,f[v][1][1][2]+son); 49 gmax(f5,f[x][1][1][1]+f[v][0][0][1]); 50 gmax(f5,f[x][1][1][1]+f[v][1][0][1]); 51 gmax(f5,f[x][1][1][1]+f[v][1][1][1]); 52 gmax(f5,t+f[v][1][1][1]); 53 gmax(f5,f[x][1][0][1]+f[v][1][1][1]); 54 55 gmax(f6,f[x][1][0][1]+f[v][0][0][1]); 56 gmax(f6,f[x][1][0][1]+f[v][1][0][1]); 57 gmax(f6,f[x][1][1][2]+f[v][1][1][1]); 58 gmax(f6,f[x][1][1][1]+f[v][1][1][2]); 59 60 t=Max(t+1,son+Max(f[v][0][0][1],Max(f[v][1][0][1],f[v][1][1][1]))); 61 son++; 62 63 f[x][0][0][1]=f1; 64 f[x][0][0][2]=f2; 65 f[x][1][1][1]=f3; 66 f[x][1][0][1]=f4; 67 f[x][1][1][2]=f5; 68 f[x][1][0][2]=f6; 69 } 70 gmax(f[x][1][1][1],son); 71 } 72 inline void init(){ 73 e=1; 74 for(int i=1;i<=n;++i) 75 memset(f[i],0,sizeof f[i]),head[i]=0; 76 } 77 inline int read(){ 78 int a=0;char ch=getchar(); 79 while(ch<'0'||ch>'9')ch=getchar(); 80 while(ch>='0'&&ch<='9')a=a*10+(ch^48),ch=getchar(); 81 return a; 82 } 83 int main(){ 84 scanf("%d%d",&T,&opt); 85 while(T--){ 86 n=read(); 87 init(); 88 for(int i=1;i<=opt;++i)read(),read(); 89 for(int i=1,u,v;i<n;++i){ 90 u=read();v=read(); 91 add(u,v);add(v,u); 92 } 93 dfs(1,0); 94 ans=Max(f[1][0][0][2],Max(f[1][1][0][2],f[1][1][1][2])); 95 printf("%d\n",ans); 96 } 97 return 0; 98 }
人生如梦亦如幻 朝如晨露暮如霞。