树型dp(2019/1/19学习笔记) by csy

树型dp(2019/1/19学习笔记)

全文代码已去掉非关键部分,请勿复制粘贴

总结:树型dp的套路掌握后代码难度不大,难度在于对状态和标记的维护。就是做了一天简单的题有点心虚

1.士兵守卫

独立集问题模版

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=5000+5;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int n,tot,ans,head[maxn],f[maxn][2];
10 void add(int x,int y)
11 {
12     e[++tot].v=y;
13     e[tot].next=head[x];
14     head[x]=tot;
15 }
16 void dp(int u,int fa)
17 {
18     f[u][0]=0,f[u][1]=1;
19     for(int i=head[u];i;i=e[i].next)
20     {
21         int v=e[i].v;
22         if(v==fa)
23             continue;
24         dp(v,u);
25         f[u][0]+=f[v][1];
26         f[u][1]+=min(f[v][0],f[v][1]);
27     }
28 }
29 int main()
30 {
31     input();
32     int x,y,m;
33     while(scanf("%d",&n)!=EOF)
34     {
35         for(int i=1;i<=n;i++)
36         {
37             x=quick();
38             m=quick();
39             for(int i=1;i<=m;i++)
40             {
41                 y=quick();
42                 add(x,y);
43                 add(y,x);
44             }
45         }
46         dp(0,-1);
47         printf("%d\n",min(f[0][1],f[0][0]));
48         tot=0;
49         for(int i=0;i<=n;i++)
50             head[i]=0;
51     }
52     return 0;
53 }

2.保卫王国

乱搞一通的44分代码

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=2e5+5;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int head[maxn],f[maxn][2],v[maxn],p[maxn];
10 char t[3];
11 int n,m,tot;
12 void add(int x,int y)
13 {
14     e[++tot].v=y;
15     e[tot].next=head[x];
16     head[x]=tot;
17 }
18 void dp(int u,int fa)
19 {
20     if(f[u][0]!=INF)
21         f[u][0]=0;
22     if(f[u][1]!=INF)
23         f[u][1]=p[u];
24     for(int i=head[u];i;i=e[i].next)
25     {
26         int vi=e[i].v;
27         if(vi==fa)
28             continue;
29         dp(vi,u);
30         if(f[u][1]==INF)
31         {
32             f[u][0]+=f[vi][1];
33             v[u]=vi;
34         }
35         else if(f[u][0]==INF)
36         {
37             f[u][1]+=min(f[vi][0],f[vi][1]);
38             v[vi]=v[u];
39         }
40         else
41         {
42             f[u][0]+=f[vi][1];
43             f[u][1]+=min(f[vi][0],f[vi][1]);
44         }
45     }
46 }
47 void query(int a,int x,int b,int y)
48 {
49     f[a][(!x)]=f[b][(!y)]=INF;
50     dp(1,0);
51     if(!x&&!y&&(v[a]==b||v[b]==a))
52         printf("-1\n");
53     else printf("%d\n",min(f[1][0],f[1][1]));
54     for(int i=1;i<=n;i++)
55         f[i][0]=f[i][1]=v[i]=0;
56 }
57 int main()
58 {
59     input();
60     int a,b,x,y;
61     n=quick();
62     m=quick();
63     scanf("%s",t);
64     for(int i=1;i<=n;i++)
65         p[i]=quick();
66     for(int i=1;i<n;i++)
67     {
68         x=quick();
69         y=quick();
70         add(x,y);
71         add(y,x);
72     }
73     for(int i=1;i<=m;i++)
74     {
75         a=quick();
76         x=quick();
77         b=quick();
78         y=quick();
79         query(a,x,b,y);
80     }
81     return 0;
82 }

3.选课

有依赖的背包问题?

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=302;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int head[maxn],p[maxn],f[maxn][maxn];
10 int n,m,tot;
11 void add(int x,int y)
12 {
13     e[++tot].v=y;
14     e[tot].next=head[x];
15     head[x]=tot;
16 }
17 void read()
18 {
19     n=quick();
20     m=quick();
21     int x,y;
22     for(int y=1;y<=n;y++)
23     {
24         x=quick();
25         add(x,y);
26         p[y]=quick();
27     }
28 }
29 int dp(int u,int fa)
30 {
31     int size=1;
32     //f[u][0]=0;
33     f[u][1]=p[u];
34     for(int i=head[u];i;i=e[i].next)
35     {
36         int v=e[i].v;
37         int s=dp(v,u);
38         size+=s;
39         for(int j=size;j>0;j--)
40             for(int k=0;k<j;k++)
41             {
42                 if(k>s)break;
43                 f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
44             }
45     }
46     return size;
47 }
48 void work()
49 {
50     dp(0,-1);
51     printf("%d",f[0][m+1]);
52 }

4.最大子树和

太简单了,都不想写。。。

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=1e6+5;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int head[maxn],f[maxn][2],a[maxn];
10 int n,ans,tot; 
11 void add(int x,int y)
12 {
13     e[++tot].v=y;
14     e[tot].next=head[x];
15     head[x]=tot;
16 }
17 void read()
18 {
19     n=quick();
20     for(int i=1;i<=n;i++)
21         a[i]=quick();
22     int x,y;
23     for(int i=1;i<n;i++)
24     {
25         x=quick();
26         y=quick();
27         add(x,y);
28         add(y,x);
29     }
30 }
31 int maxx(int x,int y,int z)
32 {
33     if(x>y)
34         y=x;
35     if(y>z)
36         z=y;
37     return z; 
38 } 
39 void dp(int u,int fa)
40 {
41     f[u][0]=0,f[u][1]=a[u];
42     for(int i=head[u];i;i=e[i].next)
43     {
44         int v=e[i].v;
45         if(v==fa)continue;
46         dp(v,u);
47         if(f[v][1]>0)
48             f[u][1]+=f[v][1]; 
49     } 
50     ans=maxx(ans,f[u][1],f[u][0]); 
51 }
52 void work()
53 {
54     dp(1,0);
55     printf("%d",ans);
56 }

5.二叉苹果树

一直卡在究竟是把权值赋边还是赋点上,其实都可以,赋边要难写一点,最后还是赋点解决了。。。

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=205;
 5 struct A
 6 {
 7     int v,w,next;
 8 }e[maxn];
 9 int f[maxn][maxn],head[maxn];
10 int n,q,tot;
11 void add(int x,int y,int z)
12 {
13     e[++tot].v=y;
14     e[tot].w=z;
15     e[tot].next=head[x];
16     head[x]=tot;
17 }
18 void read()
19 {
20     n=quick();
21     q=quick();
22     int x,y,z;
23     for(int i=1;i<n;i++)
24     {
25         x=quick();
26         y=quick();
27         z=quick();
28         add(x,y,z);
29         add(y,x,z);
30     }
31 }
32 int dp(int u,int fa,int c)
33 {
34     int size=1;
35     f[u][1]=c;
36     for(int i=head[u];i;i=e[i].next)
37     {
38         int v=e[i].v;
39         int w=e[i].w;
40         if(v==fa)
41             continue;
42         int s=dp(v,u,w);
43         size+=s;
44         for(int j=size;j>0;j--)
45             for(int k=0;k<j;k++)
46             {
47                 if(k>s+1)break;
48                 f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
49             }
50     }
51     return size;
52 }
53 void work()
54 {
55     dp(1,0,0);
56     printf("%d",f[1][q+1]);
57 }

6.战略游戏

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=3002;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int f[maxn][2],head[maxn];
10 int n,tot;
11 void add(int x,int y)
12 {
13     e[++tot].v=y;
14     e[tot].next=head[x];
15     head[x]=tot;
16 }
17 void read()
18 {
19     n=quick();
20     int x,y,k;
21     for(int i=1;i<=n;i++)
22     {
23         x=quick();
24         k=quick();
25         for(int j=1;j<=k;j++)
26         {
27             y=quick();
28             add(x,y);
29             add(y,x);
30         }
31     }
32 }
33 void dp(int u,int fa)
34 {
35     f[u][0]=0,f[u][1]=1;
36     for(int i=head[u];i;i=e[i].next)
37     {
38         int v=e[i].v;
39         if(v==fa)
40             continue;
41         dp(v,u);
42         f[u][0]+=f[v][1];
43         f[u][1]+=min(f[v][1],f[v][0]);
44     }
45 }
46 void work()
47 {
48     dp(0,-1);
49     printf("%d",min(f[0][0],f[0][1]));
50 }

7.没有上司的舞会

很有意思的一道题,细看就是独立集问题吗,但不影响它是一道很有意思的裸题。

 1 /*
 2 id:Dear_prince 
 3 */ 
 4 const int maxn=12005;
 5 struct A
 6 {
 7     int v,next;
 8 }e[maxn];
 9 int head[maxn],f[maxn][2],a[maxn];
10 int n,tot,ans;
11 void add(int x,int y)
12 {
13     e[++tot].v=y;
14     e[tot].next=head[x];
15     head[x]=tot;
16 }
17 void read()
18 {
19     n=quick();
20     for(int i=1;i<=n;i++)
21         a[i]=quick();
22     int x,y;
23     for(int i=1;i<n;i++)
24     {
25         x=quick();
26         y=quick();
27         add(y,x);
28         add(x,y);
29     }
30 }
31 int maxx(int x,int y,int z)
32 {
33     if(x>y)
34         y=x;
35     if(y>z)
36         z=y;
37     return z;
38 }
39 void dp(int u,int fa)
40 {
41     f[u][0]=0,f[u][1]=a[u];
42     for(int i=head[u];i;i=e[i].next)
43     {
44         int v=e[i].v;
45         if(v==fa)
46             continue;
47         dp(v,u);
48         f[u][0]+=max(f[v][1],f[v][0]);
49         f[u][1]+=f[v][0];
50     }
51 }
52 void work()
53 {
54     dp(1,0);
55     printf("%d",max(f[1][0],f[1][1]));
56 }

8.Party at Hali-Bula

坑点在字符串处理和确定方案数是否唯一啊。。。

实在不想弄字符串了。。。

9.重建道路

开始没看样例,以为是求刚好断出p个点,就打了个不知道什么鬼,然后连样例都没过。。。

后来发现,这就是背包啊,反着做就好了。。。

 附上76分代码,从43分写到56分再到76分也不容易啊,说不定哪天就ac啦

 1 /*
 2 id:Dear_prince 
 3 */
 4 #define INF 0x3f3f3f3f
 5 const int maxn=305;
 6 struct A
 7 {
 8     int v,next;
 9 }e[maxn];
10 int head[maxn],f1[maxn][maxn],f2[maxn][maxn];
11 int n,q,tot,ans=INF;
12 void add(int x,int y)
13 {
14     e[++tot].v=y;
15     e[tot].next=head[x];
16     head[x]=tot;
17 }
18 void read()
19 {
20     memset(f1,0x3f,sizeof(f1));
21     memset(f2,0x3f,sizeof(f2));
22     n=quick();
23     q=quick();
24     int x,y;
25     for(int i=1;i<n;i++)
26     {
27         x=quick();
28         y=quick();
29         add(x,y);
30         add(y,x);
31     }
32 }
33 int minn(int x,int y,int z)
34 {
35     if(x<y)
36         y=x;
37     if(y<z)
38         z=y;
39     return z;
40 }
41 int dp(int u,int fa)
42 {
43     int size=1,cnt=0;
44     f1[u][0]=f2[u][0]=0;
45     for(int i=head[u];i;i=e[i].next)
46     {
47         int v=e[i].v;
48         if(v==fa)
49             continue;
50         int s=dp(v,u);
51         size+=s;
52         /*for(int j=size;j>0;j--)
53             for(int k=0;k<j;k--)
54             {
55                 if(k>s)
56                     break;
57             }*/
58         f1[u][s]=1;
59     }
60     for(int i=1;i<=size;i++)
61         for(int j=1;j<=size-i;j++)
62             f2[u][i+j]=minn(min(f1[u][i],f2[u][i])+min(f1[u][j],f2[u][j]),f1[u][i+j],f2[u][i+j]);
63     return size;
64 }
65 void work()
66 {
67     dp(1,0);
68     for(int i=1;i<=n;i++)
69             ans=minn(f2[i][n-q],ans,f1[i][q]);
70     printf("%d",ans);
71 }
posted @ 2019-01-19 17:39  Achen_sy  阅读(243)  评论(1编辑  收藏  举报