Vijos p1770 大内密探 树形DP+计数

  4天终于做出来了,没错我就是这么蒟蒻。教训还是很多的。

  建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性。

  大神题解传送门 by iwtwiioi

  我的题解大家可以看注释"//"部分

  本题我用的树形DP中dp[x][fa][need]表示编号为x的节点的父亲选(1)没选(0),x的父亲需(1)不需要(0)其他节点来覆盖。

若父亲节点选了,则need肯定为0,所以不存在fa==1而need==1的状态,相当于浪费了¼的空间。毕竟数据范围比较小,而且程序要有可读性!程序要有可读性!程序要有可读性!我这么写代码不是加强了程序的可读性吗?像iwtwiioi那样用012表示状态题解和程序的可读性大大降低,大家在读题解时难免要费点劲。并没有贬义!!!╮(╯_╰)╭

my code:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 int point[100003],next[200003],v[200003],cnt=0,N,l[100003],r[100003],pre[100003],con[100003];
  6 const long long mo=1000000007;
  7 long long f[100003][2][2];
  8 int dp[100003][2][2];
  9 bool p[100003];
 10 void memsetf(){for(int i=0;i<=N;++i)for(int j=0;j<2;++j)for (int k=0;k<2;++k)f[i][j][k]=1;}
 11 void insect(int x,int y){next[cnt]=point[x];point[x]=cnt;v[cnt]=y;cnt++;}
 12 void dfs(int x)
 13 {
 14     if (x==0) return;
 15     int i,j=0;
 16     for (i=point[x];i!=-1;i=next[i])
 17      if (p[v[i]]==0)
 18      {
 19          p[v[i]]=1;
 20          if (l[x]==0) {l[x]=v[i];j=v[i];}
 21          else {r[j]=v[i];pre[v[i]]=j;j=v[i];}
 22      }
 23     dfs(j); con[j]=con[l[j]]+1;
 24     while (pre[j]!=-1){j=pre[j]; dfs(j); con[j]=con[l[j]]+con[r[j]]+1;}
 25 }
 26 void work(int x)
 27 {
 28     if (r[x]!=0) work(r[x]);
 29     if (l[x]!=0) work(l[x]);
 30     long long s=0; int num=1000000008;
 31     if ((l[x]==0)&&(r[x]==0))
 32     {
 33         dp[x][0][1]=1; dp[x][0][0]=1; dp[x][1][0]=0; return;
 34     }
 35     else
 36     if (l[x]==0)
 37     {
 38         dp[x][0][1]=1+dp[r[x]][0][0]; f[x][0][1]=f[r[x]][0][0];
 39         dp[x][0][0]=1+dp[r[x]][0][0]; f[x][0][0]=f[r[x]][0][0];
 40         dp[x][1][0]=dp[r[x]][1][0]; f[x][1][0]=f[r[x]][1][0];
 41         return;
 42     }
 43     else
 44     if (r[x]==0)
 45     {
 46         dp[x][0][1]=1+dp[l[x]][1][0]; f[x][0][1]=f[l[x]][1][0];
 47         //dp[x][0][0]=min(1+dp[l[x]][1][0],dp[l[x]][0][1]);
 48         if (1+dp[l[x]][1][0]<dp[l[x]][0][1])
 49          dp[x][0][0]=1+dp[l[x]][1][0],f[x][0][0]=f[l[x]][1][0];
 50         else
 51          if (1+dp[l[x]][1][0]>dp[l[x]][0][1])
 52           dp[x][0][0]=dp[l[x]][0][1],f[x][0][0]=f[l[x]][0][1];
 53          else
 54           dp[x][0][0]=dp[l[x]][0][1],f[x][0][0]=(f[l[x]][1][0]+f[l[x]][0][1])%mo;
 55         //dp[x][1][0]=min(1+dp[l[x]][1][0],dp[l[x]][0][0]);
 56         if (1+dp[l[x]][1][0]<dp[l[x]][0][0])
 57          dp[x][1][0]=1+dp[l[x]][1][0],f[x][1][0]=f[l[x]][1][0];
 58         else
 59          if (1+dp[l[x]][1][0]>dp[l[x]][0][0])
 60           dp[x][1][0]=dp[l[x]][0][0],f[x][1][0]=f[l[x]][0][0];
 61          else
 62           dp[x][1][0]=dp[l[x]][0][0],f[x][1][0]=(f[l[x]][1][0]+f[l[x]][0][0])%mo;
 63         return;
 64     }
 65     //dp[x][0][1]=min(dp[x][0][1],dp[l[x]][0][1]+dp[r[x]][0][1]);
 66     //dp[x][0][1]=min(dp[x][0][1],1+dp[l[x]][1][0]+dp[r[x]][0][0]);
 67     if (dp[l[x]][0][1]+dp[r[x]][0][1]<1+dp[l[x]][1][0]+dp[r[x]][0][0])
 68      dp[x][0][1]=dp[l[x]][0][1]+dp[r[x]][0][1],f[x][0][1]=(f[l[x]][0][1]*f[r[x]][0][1])%mo;
 69     else
 70      if (dp[l[x]][0][1]+dp[r[x]][0][1]>1+dp[l[x]][1][0]+dp[r[x]][0][0])
 71       dp[x][0][1]=1+dp[l[x]][1][0]+dp[r[x]][0][0],f[x][0][1]=(f[l[x]][1][0]*f[r[x]][0][0])%mo;
 72      else
 73       {
 74           dp[x][0][1]=1+dp[l[x]][1][0]+dp[r[x]][0][0];
 75         f[x][0][1]=((f[l[x]][0][1]*f[r[x]][0][1])%mo+(f[l[x]][1][0]*f[r[x]][0][0])%mo)%mo;
 76       }
 77     //dp[x][0][0]=min(dp[x][0][0],dp[l[x]][0][1]+dp[r[x]][0][0]);
 78     //dp[x][0][0]=min(dp[x][0][0],1+dp[l[x]][1][0]+dp[r[x]][0][0]);
 79     if (dp[l[x]][0][1]+dp[r[x]][0][0]<1+dp[l[x]][1][0]+dp[r[x]][0][0])
 80      dp[x][0][0]=dp[l[x]][0][1]+dp[r[x]][0][0],f[x][0][0]=(f[l[x]][0][1]*f[r[x]][0][0])%mo;
 81     else
 82      if (dp[l[x]][0][1]+dp[r[x]][0][0]>1+dp[l[x]][1][0]+dp[r[x]][0][0])
 83       dp[x][0][0]=1+dp[l[x]][1][0]+dp[r[x]][0][0],f[x][0][0]=(f[l[x]][1][0]*f[r[x]][0][0])%mo;
 84      else
 85       {
 86           dp[x][0][0]=1+dp[l[x]][1][0]+dp[r[x]][0][0];
 87           f[x][0][0]=((f[l[x]][1][0]*f[r[x]][0][0])%mo+(f[l[x]][0][1]*f[r[x]][0][0])%mo)%mo;
 88       }
 89     //dp[x][1][0]=min(dp[x][1][0],dp[l[x]][0][0]+dp[r[x]][1][0]);
 90     //dp[x][1][0]=min(dp[x][1][0],1+dp[l[x]][1][0]+dp[r[x]][1][0]);
 91     if (dp[l[x]][0][0]+dp[r[x]][1][0]<1+dp[l[x]][1][0]+dp[r[x]][1][0])
 92      dp[x][1][0]=dp[l[x]][0][0]+dp[r[x]][1][0],f[x][1][0]=(f[l[x]][0][0]*(f[r[x]][1][0]))%mo;
 93     else
 94      if (dp[l[x]][0][0]+dp[r[x]][1][0]>1+dp[l[x]][1][0]+dp[r[x]][1][0])
 95       dp[x][1][0]=1+dp[l[x]][1][0]+dp[r[x]][1][0],f[x][1][0]=(f[l[x]][1][0]*f[r[x]][1][0])%mo;
 96      else
 97       {
 98           dp[x][1][0]=1+dp[l[x]][1][0]+dp[r[x]][1][0];
 99           f[x][1][0]=((f[l[x]][0][0]*(f[r[x]][1][0]))%mo+(f[l[x]][1][0]*f[r[x]][1][0])%mo)%mo;
100       }
101 }
102 int main()
103 {
104     memset(point,-1,sizeof(point));
105     memset(next,-1,sizeof(next));
106     memset(pre,-1,sizeof(pre));
107     memset(dp,50,sizeof(dp));
108     memset(v,0,sizeof(v));
109     memset(p,0,sizeof(p));
110     memset(l,0,sizeof(l));
111     memset(r,0,sizeof(r));
112     scanf("%d\n",&N);
113     memsetf();
114     int i,x,y;
115     for (i=1;i<N;++i)
116     {
117         scanf("%d %d\n",&x,&y);
118         insect(x,y);insect(y,x);
119     }p[1]=1;dfs(1);
120     work(l[1]);
121     if (dp[l[1]][0][1]<(1+dp[l[1]][1][0]))
122      printf("%d\n%I64d\n",dp[l[1]][0][1],f[l[1]][0][1]);
123     else
124      if (dp[l[1]][0][1]>(1+dp[l[1]][1][0]))
125       printf("%d\n%I64d\n",1+dp[l[1]][1][0],f[l[1]][1][0]);
126      else
127       printf("%d\n%I64d\n",1+dp[l[1]][1][0],(f[l[1]][0][1]+f[l[1]][1][0])%mo);
128     return 0;
129 }

P1770大内密探

Accepted

标签:[显示标签]

背景

大内密探,负责秘密保护皇上,还有保护皇宫内外一切产业。——大内密探零零七

描述

在古老的皇宫中,有N个房间以及N-1条双向通道,每条通道连接着两个不同的房间,所有的房间都能互相到达。皇宫中有许多的宝物,所以需要若干个大内密探来守护。一个房间被守护当切仅当该房间内有一名大内密探或者与该房间直接相邻的房间内有大内密探。

现在身为大内密探零零七的你想知道要把整个皇宫守护好至少需要多少名大内密探以及有多少种安排密探的方案。两种方案不同当且仅当某个房间在一种方案有密探而在另一个方案内没有密探。

格式

输入格式

第一行一个正整数N.(1<=N<=100000)
后面N-1行,每行两个正整数a和b,表示房间a和房间b之间有一条无向通道。

房间的编号从1到N

输出格式

第一行输出正整数K,表示最少安排的大内密探。

第二行输出整数S,表示有多少种方案安排最少的密探,由于结果可能较大,请输出方案数mod 1000000007的余数。

样例1

样例输入1[复制]

7
2 1
3 1
4 2
5 1
6 2
7 6

样例输出1[复制]

3
4

限制

每个测试点1s

提示

30%保证:n <= 10
70%保证:n <= 1000
100%保证:n <= 100000

时间: 2024-11-29 02:19:44

Vijos p1770 大内密探 树形DP+计数的相关文章

Vijos p1518河流 树形DP

https://vijos.org/p/1518 这题代码我基本是抄的,实在太难想了.但是也学到了一些东西. 比如:多叉树转二叉树存,这个细细一想,确实使得在dfs的时候,实现起来方便很多. 说一说具体 dfs的思路,思路和网上那个一模一样的,我刚学树形dp,可能上网看看总结下套路比较好. 设dfs(cur, hasPoint, k, dis)表示,现在处理到cur这个节点,离cur最近的那个仓库节点是hasPoint, 剩下k次设置仓库的机会,还有就是cur的爸爸距离hasPoint的距离.

vijos 1180 选课 树形DP

描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得相应的学分. 在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在选修了<Windows操作基础>之后才能选修.我们称<Windows操作基础>是<Frontpage>的先修课

【vijos】1770 大内密探(树形dp+计数)

https://vijos.org/p/1770 不重不漏地设计状态才能正确的计数QAQ 虽然可能最优化是正确的,但是不能保证状态不相交就是作死.... 之前设的状态错了... 应该设 f[i][0]表示i点不取且至少有一个儿子取,且保证i点被覆盖 f[i][1]表示i点取儿子任意,且保证i点被覆盖 f[i][2]表示i点不取且i点的儿子也不取,保证i点不被覆盖!(即留给父亲覆盖) f[i][2]表示i点不取且儿子也不取.并不是表示i点不取儿子任意!!!!!!!!!!要不然这样会出现交的情况!假

【vijos】1892 树上的最大匹配(树形dp+计数)

https://vijos.org/p/1892 这个必须得卡评测机+手动开栈才能卡过QAQ 手动开栈我百度的... int size=256<<20; //256MB char *p=(char*)malloc(size)+size; __asm__("movl %0, %%esp\n" :: "r"(p)); 然后我交了无数发,然后才卡过.... 我们设状态 f[i][0]表示i节点与儿子的边一个也不选 f[i][1]表示i节点只选一条与儿子的边 g

CodeForces 158E Phone Talks 树形dp+计数

题目链接:点击打开链接 题意:给定n个点的树,常数d 给出每个点的权值,问有多少种划分方法使得划分后每个连通块里的最大权值-最小权值<=d 思路:点击打开链接 枚举每个点i 使得i是集合中的最小值. 则枚举时已经使得i是最小值,然后这个问题就变成单纯的划分问题了,上面链接里的题解已经很详尽了 import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayDeque; import java.ut

UVA 11174 Stand in a Line 树形dp+计数

题目链接:点击打开链接 题意:白书的P103. 加个虚根就可以了...然后就是一个多重集排列. import java.io.PrintWriter; import java.util.ArrayList; import java.util.Scanner; public class Main { static int N = 40100; ArrayList<Integer>[] G = new ArrayList[N]; static long mod = 1000000007; long

Codeforces 486D Valid Sets 树形dp+计数

题目链接:点击打开链接 题意:给定常数d 和 n,表示n个点的树,每个点有点权 问:有多少个点集使得点集中的点两两可达且最大点权-最小点权<=d 思路: 对于每个点,计算包含这个点且这个点作为点集中的最小点权时的个数,枚举每个点. import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

vijos 1313 金明的预算方案 树形DP

描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:主件 附件电脑 打印机,扫描仪书柜 图书书桌 台灯,文具工作椅 无如果要买归类为附件的物品,必须先买该附件所属的主件.每个主件可以有0个.1个或2个附件.附件不再有从属于自己的附件.金明