hdu 4912 Paths on the tree (LCA+贪心)
来源:互联网 发布:windows装linux双系统 编辑:程序博客网 时间:2024/05/09 19:35
题意:
一颗无根树上有很多条简单路径,已知这些简单路径的两个端点,求最多能选择多少条路径,
使得任意两条路径没有交点。(交点指此点既在路径a上,又在路径b上)。
算法:
怎样来确定路径呢?首先从端点u走到端点v必定要经过u和v的lca,即lca(u,v)必定在以u、v为端点
的简单路径上。那么我们可以通过每条路径端点的lca的深度从大到小排序。
为了选择的个数更多,就要尽量避免冲突,故利用贪心的思想,从lca大的开始选择,每次选择后,
把路径上的所有点都标记。这样下次就不会选择到一条有重复点的路径了。
关于lca有离线的tarjan算法(dfs+并查集) 和在线的基于dfs+ rmq的st算法 的倍增算法。
个人觉得lca离线算法比较好理解。
算法主体
void tarjan(int x,int f){ fa[x] = x; vis[x] = true; //有时可以不要,直接用lev[]数组标记走没走过 for(int i=0;i<q[u].size();i++) { int v = q[u][i]; //询问LCA(u,v) if(vis[x]) lca[u][v] = lca[v][u] = root(v); //root(v)即找v集合的根节点 } //这里如果点的个数在100000的数量级或以上,二维的lca[][]是开不下的 //可以把第二个点v和询问的编号id作为pair放入q[u]数组中,这样就可以用lca[id] = root(v)记录了 for(int i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if(v == f) continue; if(!vis[v]) { lev[v] = lev[u]+1; tarjan(v); fa[v] = u; //将v并入u集合 } }}
在线算法我学了一下午也没有特别深入的理解,我准备再学下rmq,这样再回头理解这个
LCA的在线算法。
我现在能理解的全部都注释到代码中了!
#include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<algorithm>#include<queue>#define maxn 100010using namespace std;struct edge{ int to,next;}e[maxn<<1];struct node{ int u,v,lca;}t[maxn];int head[maxn],cnt,n;int lev[maxn],fa[maxn][20];bool vis[maxn];bool cmp(node x,node y){ return lev[x.lca]>lev[y.lca];}void init(){ memset(head,-1,sizeof(head)); cnt = 0;}void add(int x,int y){ e[cnt].to = y; e[cnt].next = head[x]; head[x] = cnt++;}void bfs(int x){ queue<int> q; lev[x] = 0; fa[x][0] = x; q.push(x); while(!q.empty()) { int u = q.front(); q.pop(); for(int i=1;i<20;i++) fa[u][i] = fa[fa[u][i-1]][i-1]; for(int i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if(v==fa[u][0]) continue; fa[v][0] = u; lev[v] = lev[u]+1; q.push(v); } }}int LCA(int x,int y){ if(lev[x]<lev[y]) //如果x的深度比y的深度小则交换x和y { int tmp = x; x = y; y = tmp; } for(int i=19;i>=0;i--) { if((1<<i)&(lev[x]-lev[y])) //如果x和y不在同一深度,x往上移动到他的祖先节点 x = fa[x][i]; } if(x==y) return x; //如果y在x到根节点之间的路径上,则lca(x,y) = y; for(int i=19;i>=0;i--) { if(fa[x][i]!=fa[y][i]) //x和y到了同一深度后,继续往上移动到祖先节点 { //直到两个的祖先节点相同则找到lca x = fa[x][i]; y = fa[y][i]; } } return fa[x][0];}void dfs(int u){ vis[u] = true; for(int i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if(vis[v] || lev[v]<lev[u]) continue; //由于是无根树,所以只能把深度大于当前节点的子树中的点标记 dfs(v); }}int main(){ //freopen("1.txt","r",stdin); int m,a,b; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } bfs(1); for(int i=0;i<m;i++) { scanf("%d%d",&t[i].u,&t[i].v); t[i].lca = LCA(t[i].u,t[i].v); } sort(t,t+m,cmp); memset(vis,0,sizeof(vis)); int ans = 0; for(int i=0;i<m;i++) { int xx = t[i].u,yy = t[i].v,zz = t[i].lca; if(!vis[xx] && !vis[yy]) { ans++; dfs(zz); } } printf("%d\n",ans); } return 0;}//在线算法 LCA倍增算法
#include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<algorithm>#define maxn 100010using namespace std;struct edge{ int to,next;}e[maxn<<2];struct node{ int u,v,cs;}t[maxn];int cnt,head[maxn],lev[maxn],fa[maxn],n,lca[maxn];bool vis[maxn];vector<pair<int,int> > q[maxn];void init(){ for(int i=1;i<=n;i++) q[i].clear(); cnt = 0; memset(head,-1,sizeof(head));}void add(int x,int y){ e[cnt].to = y; e[cnt].next = head[x]; head[x] = cnt++;}bool cmp(node x,node y){ return lev[x.cs]>lev[y.cs];}int root(int x){ if(fa[x]==x) return x; else fa[x] = root(fa[x]); return fa[x];}void dfs(int u,int f){ fa[u] = u; pair<int,int> pp; for(int i=0;i<q[u].size();i++) { pp = q[u][i]; int t1 = pp.first,t2 = pp.second; if(lev[t1]==-1) continue; t[t2].cs = root(t1); } for(int i=head[u];i!=-1;i=e[i].next) { int v = e[i].to; if(v==f) continue; lev[v] = lev[u]+1; dfs(v,u); fa[v] = u; }}void dfs1(int x){ vis[x] = true; for(int i=head[x];i!=-1;i=e[i].next) { int v = e[i].to; if(vis[v] || lev[v]<lev[x]) continue; dfs1(v); }}int main(){ //freopen("1.txt","r",stdin); // freopen("11.txt","w",stdout); int m,a,b; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); q[a].push_back(make_pair(b,i)); q[b].push_back(make_pair(a,i)); t[i].u = a; t[i].v = b; } memset(lev,-1,sizeof(lev)); lev[1] = 0; dfs(1,-1); sort(t,t+m,cmp); int ans = 0; memset(vis,0,sizeof(vis)); for(int i=0;i<m;i++) { int xx = t[i].u,yy = t[i].v,zz = t[i].cs; if(!vis[xx] && !vis[yy]) { ans++; dfs1(zz); } } printf("%d\n",ans); } return 0;}
0 0
- HDU 4912 Paths on the tree LCA 排序贪心
- hdu 4912 Paths on the tree(lca+贪心)
- hdu 4912 Paths on the tree lca+贪心
- hdu 4912 Paths on the tree LCA + 贪心
- HDU 4912 - Paths on the tree (LCA 贪心)
- hdu 4912 Paths on the tree (LCA+贪心)
- HDU 4912 Paths on the tree (LCA+贪心)
- HDU 4912 Paths on the tree 贪心+lca
- 【HDU】4912 Paths on the tree 离线LCA+贪心
- HDU 4912 Paths on the tree(LCA+贪心)
- hdu 4912Paths on the tree (LCA)
- hdu4912 Paths on the tree --- LCA贪心
- HDU4912 Paths on the tree(数据结构,lca,贪心)
- hdu 4912 Paths on the tree(树链剖分+贪心)
- HDU 4912(Paths on the tree-树上取链,贪心)
- HDU 4912 Paths on the tree
- hdu 4912 Paths on the tree
- HDU-4912-Paths on the tree
- 用高富帅描述对象构造先后
- Android应用开发SharedPreferences存储数据的使用方法
- hadoop源码[0]-初衷和各种资源
- openwrt下wifi设置详细过程
- 图片/容器/字体 透明度【opacity:0.4; filter:alpha(opacity=40)】
- hdu 4912 Paths on the tree (LCA+贪心)
- [转载内容]调查发现半数人习惯单手持握手机
- Android新编译的内核驱动模块不能被init加载原因解决
- 说说Android应用的persistent属性
- poj 3481 Double Queue splay
- hdoj 2029 Palindromes _easy version(回文串)
- PythonOpencv-分类器—SVM,KNearest,RTrees,Boost,MLP
- POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)
- 栈和队列B题