摧毁树状图
来源:互联网 发布:淘宝黄金戒指 编辑:程序博客网 时间:2024/04/27 22:43
摧毁树状图
有一颗
n 个节点的树,可以将树上的两条链(边不得共用,点可以)上的节点删除,问删除后最多能得到最多的连通块。
n≤105
吐槽
这道题可以说是树上动规的集大成之题目,细节部分实在很容易考虑不全面,不过出题人还是很良心的,给了大力搜索
这种神题我怎么可能做出来,都是考完后照着大神的题解改的,不过我感觉我把代码加了些注释应该更明了一些。
预备
首先,当我们开心地敲完
在设计之前呢,我们首先要考虑一条链的情况:
设
状态设计
经过巧(wu)妙(nao)的设计,我们对一个节点记录一下状态:
f(u,0) :以u 为根的子树,有一条可向上延伸的链的最大答案;f(u,1) :……,不含u 的完整链的最大答案;f(u,2) :……,含u ……f(u,3) :……,一条完整的链、一条可向上延伸的链的最大答案;f(u,4) :……,不含u 的完整的两条链的最大答案;f(u,5) :……,含u ……
状态转移 状态设计一时爽,状态转移火葬场
嘛,总之状态的转移很繁琐就是了,我真的没有信心在考试的时候考虑到所有的情况(可能是我太弱了),情况非常多,代码里都注释上来,搭配一下内容应该很容易食用了。
f(u,0) - 从儿子转移上来
- 另起炉灶
f(u,1) - 从儿子转移上来
f(v,2)+1
f(u,2) - 选两个
f(v,0) 拼起来
- 选两个
f(u,3) - 从儿子转移上来
- 完整的链 +
f(v,0) - 三条
f(v,0)
f(u,4) - 同一儿子转移上来
- 不同儿子……
- 多种情况,注意
±1
- 多种情况,注意
f(u,5) - 两个
f(u,3) 拼起来 - 四条
f(v,0) - 从一个儿子转移上来一整条链,然后选两条
f(v,0) 拼一起
- 两个
具体实现的时候注意
mx 的初值可能为0 或−∞ ,这取决于mx 所代表的值是否可以不选,具体见代码。
/************************************************************** Problem: 4871 User: zhangche0526 Language: C++ Result: Accepted Time:2936 ms Memory:7932 kb****************************************************************/#include<iostream>#include<cstdio>#include<cstring>typedef long long ll;int read();const int MAXN=1e5+5,INF=0x0f0f0f0f;int n;struct E{int next,to;} e[MAXN<<1];int ecnt,G[MAXN];void addEdge(int u,int v){e[++ecnt]=(E){G[u],v};G[u]=ecnt;}void addEdge2(int u,int v){addEdge(u,v);addEdge(v,u);}int f[MAXN][6],scnt[MAXN];//scnt is actually sonNumber - 1;void calScnt(int u,int la){ scnt[u]=-1; for(int i=G[u];i;i=e[i].next) if(e[i].to!=la) ++scnt[u],calScnt(e[i].to,u);}inline void upd(int &x,const int &y){if(y>x) x=y;}void dp(int u,int la){ memset(f[u],-0x3f,sizeof(f[u])); int i; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) dp(e[i].to,u);//f(u,0)//{ f[u][0]=scnt[u]; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) upd(f[u][0],f[e[i].to][0]+scnt[u]);//}//f(u,1)//{ for(i=G[u];i;i=e[i].next) if(e[i].to!=la) upd(f[u][1],f[e[i].to][2]+1), upd(f[u][1],f[e[i].to][1]);//}//f(u,2)//{ int mx1=0; f[u][2]=scnt[u]+1; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) upd(f[u][2],mx1+f[e[i].to][0]+scnt[u]+1), upd(mx1,f[e[i].to][0]);//}//f(u,3)//{// case 1 for(i=G[u];i;i=e[i].next) if(e[i].to!=la) upd(f[u][3],f[e[i].to][3]+scnt[u]);// case 2 int mx2=0;mx1=-INF; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) { int v=e[i].to; upd(f[u][3],mx1+f[v][0]+scnt[u]); upd(f[u][3],f[v][1]-1+mx2+scnt[u]); upd(f[u][3],f[v][2]-1+mx2+scnt[u]); upd(mx1,f[v][1]-1),upd(mx1,f[v][2]-1); upd(mx2,f[v][0]); } // case 3 int mx3=0;mx1=mx2=0; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) { int val=f[e[i].to][0]; if(val>mx1) std::swap(mx1,val); if(val>mx2) std::swap(mx2,val); if(val>mx3) std::swap(mx3,val); } upd(f[u][3],mx1+mx2+mx3+scnt[u]);//}//f(u,4)//{// case 1 for(i=G[u];i;i=e[i].next) if(e[i].to!=la) upd(f[u][4],f[e[i].to][5]+1), upd(f[u][4],f[e[i].to][4]);// case2 mx1=-INF,mx2=-INF; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) { int v=e[i].to; upd(f[u][4],f[v][1]+mx1-1); upd(f[u][4],f[v][1]+mx2); upd(f[u][4],f[v][2]+mx1); upd(f[u][4],f[v][2]+mx2+1); upd(mx1,f[v][1]),upd(mx2,f[v][2]); }//}//f(u,5)//{// case 1 mx1=-INF,mx2=0; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) { upd(f[u][5],mx1+f[e[i].to][0]+scnt[u]+1); upd(f[u][5],mx2+f[e[i].to][3]+scnt[u]+1); upd(mx1,f[e[i].to][3]),upd(mx2,f[e[i].to][0]); }// case 2 int mx4=0;mx1=mx2=mx3=0; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) { int val=f[e[i].to][0]; if(val>mx1) std::swap(mx1,val); if(val>mx2) std::swap(mx2,val); if(val>mx3) std::swap(mx3,val); if(val>mx4) std::swap(mx4,val); } upd(f[u][5],mx1+mx2+mx3+mx4+scnt[u]+1);// case 3 static int sons[MAXN];int sz=0; sons[0]=-1; for(i=G[u];i;i=e[i].next) if(e[i].to!=la) sons[++sz]=e[i].to; static int preSgMx[MAXN],preDbMx[MAXN],sufSgMx[MAXN],sufDbMx[MAXN]; preSgMx[0]=preDbMx[0]=sufSgMx[sz+1]=sufDbMx[sz+1]=0; for(i=1;i<=sz;i++) preDbMx[i]=std::max(preDbMx[i-1],f[sons[i]][0]+preSgMx[i-1]), preSgMx[i]=std::max(preSgMx[i-1],f[sons[i]][0]); for(i=sz;i;i--) sufDbMx[i]=std::max(sufDbMx[i+1],f[sons[i]][0]+sufSgMx[i+1]), sufSgMx[i]=std::max(sufSgMx[i+1],f[sons[i]][0]); for(i=1;i<=sz;i++) { int mx=std::max(f[sons[i]][1],f[sons[i]][2]); upd(f[u][5],mx+preDbMx[i-1]+scnt[u]); upd(f[u][5],mx+sufDbMx[i+1]+scnt[u]); upd(f[u][5],mx+preSgMx[i-1]+sufSgMx[i+1]+scnt[u]); }//}}int main(){ int T=read(),x=read(); while(T--) { int i; n=read(); if(x>=1) read(),read(); if(x==2) read(),read(); ecnt=0;memset(G,0,sizeof(G)); for(i=1;i<n;i++) { int u=read()-1,v=read()-1; addEdge2(u,v); } calScnt(0,-1); dp(0,-1); printf("%d\n",std::max(f[0][4],f[0][5])); } return 0;}int read(){ char c;int flag=1,res=0; do c=getchar();while(c!='-'&&(c<'0'||c>'9')); if(c=='-') flag=-1;else res=c-'0';c=getchar(); while(c>='0'&&c<='9'){res=res*10+c-'0';c=getchar();} return flag*res;}
阅读全文
1 0
- 摧毁树状图
- 【BZOJ4871】【SHOI2017】摧毁“树状图”
- 4871: [Shoi2017]摧毁“树状图”
- 【SHOI&SXOI2017】bzoj4871 摧毁“树状图”
- POJ 3041 Asteroids(摧毁小行星,二分图)
- 摧毁自己
- 摧毁图状树
- 摧毁网络
- 摧毁数组
- 甘肃甘南7万间民房遭地震摧毁 救灾物资缺乏(图)
- 黑鹰被摧毁
- 怎样摧毁互联网?
- 怎样摧毁互联网?
- NYOJ 641 摧毁网络
- 如何摧毁程序员效率
- 如何摧毁程序员效率
- 如何摧毁整个互联网?
- 龙卷风摧毁停车场题解
- Leetcode 97Interleaving String
- C++实现单链表
- 杭电acm—2137 circumgyrate the string
- C++中声明与定义的关系
- 数组的常见操作:冒泡排序 选择排序与取最值
- 摧毁树状图
- uboot移植
- 功夫小子实践开发-菜单场景之游戏秘籍场景的分析和实现
- P1414 又是毕业季Ⅱ
- 【C++】各种排序运行时间的测试
- 机器学习和数据挖掘(9):线性模型
- 2017年8月8日提高组T3 题目
- 如何获取data-id中的值
- 剑指offer之斐波那契数列