【图论】点分治总结&POJ2114Boatherds题解
来源:互联网 发布:空间绑定域名 编辑:程序博客网 时间:2024/06/09 23:30
点分治
适用问题:
统计一棵树上的路径的问题,因为树上的路径需要一个起点和终点来确定,所以朴素算法的复杂度常常为
大体思路:
首先我们引入一个“树的重心”的概念
定义一个点的权值为它的最大子树的大小
权值最小的一个点(或许有多个,但在点分治中并不在意这些)。
有一个很显然的性质:以重心为根,最大子树的大小,必然不大于树中总点数的一半
用反证法可以很容易地证明:
如果某个子树的节点个数大于总点数一半,那么那个节点的权值一定会小于等于总点数的一半,即当前的“重心”的权值并非最小,不符合定义。
这样一来,每次操作我们统计所有与重心相连接的路径,再将重心消除,形成一个森林,再递归操作下去,在
例题:POJ2114Boatherds
题目大意:给出一颗树,求树上是否存在一条总和为k的路径。
分析:
按照点分治的思路,从每一个(不同树的)重心出发,找一颗子树,存储从重心到达当前点的路径和,询问k-sum是否存在于其他的子树上,若存在,就返回结束。
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<set>#include<vector>#define SF scanf#define PF printf#define MAXN 10010#define MAXM 10000010using namespace std;vector<int> a[MAXN],p[MAXN];int used[MAXM],times;int sumx[MAXN],sumy[MAXN],foc[MAXN],cnt,n,k,del[MAXN];bool vis[MAXN];int dp(int x,int fa){ vis[x]=1; for(int i=0;i<a[x].size();i++) if(a[x][i]!=fa&&del[a[x][i]]!=1) sumx[x]+=dp(a[x][i],x)+1; return sumx[x];}int dp0(int x,int fa,int sum){ sumy[x]=sum-sumx[x]-1; for(int i=0;i<a[x].size();i++){ if(a[x][i]==fa||del[a[x][i]]==1) continue; sumy[x]=max(sumx[a[x][i]]+1,sumy[x]); } int x1=x; for(int i=0;i<a[x].size();i++){ if(a[x][i]==fa||del[a[x][i]]==1) continue; int ans1=dp0(a[x][i],x,sum); if(sumy[ans1]<sumy[x1]) x1=ans1; } return x1;}void find_foc(){ cnt=0; memset(foc,0,sizeof foc); memset(sumy,0,sizeof sumy); memset(sumx,0,sizeof sumx); memset(vis,0,sizeof vis); for(int i=1;i<=n;i++){ if(del[i]==1){ foc[++cnt]=i; continue; } if(vis[i]==0){ dp(i,0); foc[++cnt]=dp0(i,0,sumx[i]+1); } }}bool dfs(int x,int fa,int sum,int rootx){ //if(used.count(k-sum)!=0) // return 1; if(k>=sum&&used[k-sum]==rootx) return 1; for(int i=0;i<a[x].size();i++) if(del[a[x][i]]!=1&&a[x][i]!=fa&&dfs(a[x][i],x,sum+p[x][i],rootx)==1) return 1; return 0;}void update(int x,int fa,int sum,int rootx){ if(sum<=k) used[sum]=rootx; //used.insert(sum); for(int i=0;i<a[x].size();i++) if(del[a[x][i]]!=1&&a[x][i]!=fa) update(a[x][i],x,sum+p[x][i],rootx);}bool solve(int x){ if(del[x]==1) return 0; //used.clear(); //used.insert(0); used[0]=times; for(int i=0;i<a[x].size();i++){ if(del[a[x][i]]==1) continue; if(dfs(a[x][i],x,p[x][i],times)==1) return 1; update(a[x][i],x,p[x][i],times); } return 0;}int main(){ //freopen("data.in","r",stdin); int x,val; while(SF("%d",&n)!=EOF){ if(n==0) break; for(int i=1;i<=n;i++){ a[i].clear(); p[i].clear(); } for(int i=1;i<=n;i++){ SF("%d",&x); while(x){ SF("%d",&val); a[i].push_back(x); p[i].push_back(val); a[x].push_back(i); p[x].push_back(val); SF("%d",&x); } } SF("%d",&k); while(k!=0){ memset(del,0,sizeof del); find_foc(); int flag=0; while(cnt<n){ for(int i=1;i<=cnt;i++){ x=foc[i]; times++; if(solve(x)){ flag=1; break; } del[x]=1; } if(flag) break; find_foc(); } if(flag==0) PF("NAY\n"); else PF("AYE\n"); SF("%d",&k); times++; } PF(".\n"); }}
阅读全文
0 0
- 【图论】点分治总结&POJ2114Boatherds题解
- 点分治总结
- 【点分治总结】
- 点分治总结
- 点分治总结
- 【BZOJ】【P1468】【Tree】【题解】【点分治】
- 【BZOJ】【P2599】【IOI2011】【Race】【题解】【点分治】
- Poj1741[Tree]题解--点分治||Treap
- BZOJ2152 聪聪可可 点分治题解
- BZOJ 2599: [IOI2011]Race 点分治题解
- BZOJ 1468: Tree 点分治题解
- 点分治专题——bzoj 1468 &bzoj 2152 题解
- 【BZOJ】【P3697】【采药人的路径】【题解】【点分治】
- 【BZOJ】【P2152】【聪聪可可】【题解】【点分治】
- BZOJ 1316: 树上的询问 点分治题解
- 树分治-点分治
- 点分治
- 点分治
- 禁止横竖屏切换、强制横竖屏
- Spring 定时任务之 @Scheduled cron表达式
- jqweui的picker动态加载数据
- 利用 socket.io 实现消息实时推送
- 第一次构建个人网站的记录
- 【图论】点分治总结&POJ2114Boatherds题解
- Qt--Q_GLOBAL_STATIC
- centos一键安装redmine
- PSR-4自动加载器
- servlet请求转发、重定向路径
- VUE项目目录介绍
- DNS域名系统
- BZOJ2152: 聪聪可可 【点分治】
- SpringBoot定时任务说明