uva11354 最小瓶颈路及其应用
来源:互联网 发布:快手下载软件 编辑:程序博客网 时间:2024/06/09 23:46
关键词:LCA,最小瓶颈路,树上路径问题、次小生成树
询问任意两点间最小瓶颈路(最大边最小)
法一:
1.dp[u][v]:MST上u,v路径最小瓶颈路 O(n^2)
2.每组询问输出dp[u][v] O(q)
本题n最大可取50000,此法不可取
法二:
1.anc[u][i]:MST有根树中,u的第2^i个祖先;maxcost[u][i]:u到第2^i个祖先路径上的瓶颈(最长边) O(n*logn)
2.每组询问,查找u和v分别到它们公共祖先路径上的瓶颈的最大值 O(logn*q)
询问复杂度上升,但是可以接受。
心得:树上路径问题。先转化为有根树,再用LCA解决多组询问问题(前提是一般dp的预处理复杂度较高,无法完成,而LCA预处理复杂度较低)
应用:边权减小,询问MST变化(n很大,无法O(n^2)预处理)
变题:给定一棵树,每个顶点有一个权值,询问某两点路径上的最大权值(n<=50000,q<=100000)
1.建立有根树,边权定义为子节点的点权,只有根节点附加权值 O(n)
2.同上求anc[u][i]和maxcost[u][i] O(n*logn)
3.询问时,加一个特判,如果两点公共祖先是根节点,则需要比较ans和根节点权值的大小,取较大值即可 O(q*logn)
#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<math.h>#define ll long long#define sf scanf#define pf printf#define INF 1<<29#define mem(a,b) memset(a,b,sizeof(a))#define lowbit(x) x&(-x)#define maxn 50010#define maxm 100010const ll mol=1000000007;using namespace std;int n,m,q;struct Node{ int u,v,w; bool operator<(const Node&rhs)const{ return w<rhs.w; }}node[maxm<<1];struct Edge{ int to,next,w;}edge[maxn<<2];int head[maxn],tot,mst;int p[maxn];int father[maxn],depth[maxn],cost[maxn];int anc[maxn][30],maxcost[maxn][30];void add(int u,int v,int w){ edge[tot].to=v,edge[tot].w=w,edge[tot].next=head[u],head[u]=tot++;}int Find(int x){ return (p[x]==x)?x:Find(p[x]); }void kruscal(){ for(int i=1;i<=n;i++) p[i]=i; sort(node+1,node+m+1); mem(head,-1),tot=0,mst=0; for(int i=1;i<=m;i++){ int u=node[i].u,v=node[i].v,w=node[i].w; int x=Find(u),y=Find(v); if(x!=y){ p[x]=y;mst+=w; add(u,v,w),add(v,u,w); } }}void root(int u,int fa,int w){ father[u]=fa,cost[u]=w; if(fa!=-1) depth[u]=depth[fa]+1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to,w=edge[i].w; if(v!=fa) root(v,u,w); }}void preprocess(){ for(int i=1;i<=n;i++){//大括号位置打错了TAT... anc[i][0]=father[i],maxcost[i][0]=cost[i]; for(int j=1;(1<<j)<=n;j++) anc[i][j]=-1; } for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) if(anc[i][j-1]!=-1){//判断条件很重要! anc[i][j]=anc[anc[i][j-1]][j-1]; maxcost[i][j]=max(maxcost[i][j-1],maxcost[anc[i][j-1]][j-1]); }}int query(int u,int v){ if(depth[u]<depth[v]) swap(u,v);//交换u,v,而不是交换u,v的深度 int log,ans=-INF;//记录u深度的二进制最大位数 for(log=0;(1<<log)<=depth[u];log++); log--; for(int i=log;i>=0;i--)//上升到同一高度 if(depth[u]-(1<<i)>=depth[v]) { ans=max(ans,maxcost[u][i]);u=anc[u][i]; } if(u==v) return ans;//v是u的祖先---特判!!! for(int i=log;i>=0;i--)//同步上升到公共祖先节点的子节点 if(anc[u][i]!=-1&&anc[u][i]!=anc[v][i]){ ans=max(ans,maxcost[u][i]),u=anc[u][i]; ans=max(ans,maxcost[v][i]),v=anc[v][i]; } ans=max(ans,cost[u]),ans=max(ans,cost[v]); return ans;}int main(){ //freopen("a.txt","r",stdin); int t=0; while(scanf("%d%d",&n,&m)!=EOF){ if(t!=0) printf("\n");//输出问题---最后一组不能输出换行,换行必须写在前面 t++; for(int i=1;i<=m;i++) scanf("%d%d%d",&node[i].u,&node[i].v,&node[i].w); kruscal(); depth[1]=0; root(1,-1,0); preprocess(); scanf("%d",&q); while(q--){ int u,v; scanf("%d%d",&u,&v); printf("%d\n",query(u,v)); } }}
利用最小瓶颈路结论可以求出次小生成树
O(nlogn)预处理,O(mlogn)询问
#include<stdio.h>#include<string.h>#include<iostream>#include<vector>#include<queue>#include<algorithm>#define maxm 1000000#define maxn 110#define rad 10000#define INF 1<<28#define ll long long#define rad 10000#define mem(a,b) memset(a,b,sizeof(a))using namespace std;int t,n,m,mst;struct Node{ int u,v,w; bool operator<(const Node&rhs)const{ return w<rhs.w; }}node[maxn*maxn];struct Edge{ int to,next,w;}edge[maxn*maxn];int head[maxn],tot,p[maxn],vis[maxn][maxn],fa[maxn],cost[maxn];int maxc[maxn][20],maxc2[maxn][20],anc[maxn][20],depth[maxn];void add(int u,int v,int w) { edge[tot].to=v,edge[tot].next=head[u],edge[tot].w=w,head[u]=tot++; }int Find(int u) { return p[u]==u?u:(p[u]=Find(p[u])); }void kruscal(){ for(int i=1;i<=n;i++) p[i]=i; mst=0,mem(vis,0),mem(head,-1),tot=0; for(int i=1;i<=m;i++){ int x=Find(node[i].u),y=Find(node[i].v); if(x!=y){ p[x]=y,mst+=node[i].w; vis[node[i].u][node[i].v]=vis[node[i].v][node[i].u]=1; add(node[i].u,node[i].v,node[i].w),add(node[i].v,node[i].u,node[i].w); } }}void dfs(int u,int f,int w){ cost[u]=w,fa[u]=f,depth[u]=(f==-1)?0:(depth[f]+1); for(int i=i=head[u];i!=-1;i=edge[i].next) if(edge[i].to!=f) dfs(edge[i].to,u,edge[i].w);}void process(){ for(int i=1;i<=n;i++){ anc[i][0]=fa[i],maxc[i][0]=cost[i],maxc2[i][0]=cost[i]; for(int j=1;(1<<j)<n;j++) anc[i][j]=-1; } for(int j=1;(1<<j)<n;j++) for(int i=1;i<=n;i++) if(anc[i][j-1]!=-1){ int a=anc[i][j-1]; anc[i][j]=anc[a][j-1]; maxc[i][j]=max(maxc[i][j-1],maxc[a][j-1]); }}int query(int u,int v){ int tmp,log,i; if(depth[u]<depth[v]) swap(u,v); for(log=1;(1<<log)<=depth[u];log++); log--; int ans=-INF; for(int i=log;i>=0;i--) if(depth[u]-depth[v]>=(1<<i)) { ans=max(ans,maxc[u][i]);u=anc[u][i]; } if(u==v) return ans; for(int i=log;i>=0;i--) if(anc[u][i]!=-1&&anc[u][i]!=anc[v][i]){ ans=max(maxc[u][i],ans),u=anc[u][i]; ans=max(maxc[v][i],ans),v=anc[v][i]; } ans=max(ans,cost[u]),ans=max(ans,cost[v]); return ans;}int main(){ //freopen("a.txt","r",stdin); scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&node[i].u,&node[i].v,&node[i].w); sort(node+1,node+m+1); kruscal(); dfs(1,-1,0);//转化为有根树 process();//倍增法预处理x的第i个祖先及路径上的最长边和次长边 int ans=INF; for(int i=1;i<=m;i++){ int u=node[i].u,v=node[i].v,w=node[i].w; if(!vis[u][v]){ int tmp=mst+w-query(u,v); if(tmp<ans) ans=tmp; } } printf("%d %d\n",mst,ans); }}
求出最长边和严格次长边解决严格次小生成树问题
#include<stdio.h>#include<string.h>#include<iostream>#include<vector>#include<queue>#include<algorithm>#define maxm 500000#define maxn 100100#define rad 10000#define INF 1<<28#define ll long long#define rad 10000#define mem(a,b) memset(a,b,sizeof(a))using namespace std;int t,n,m,mst;struct Node{ int u,v,w; bool operator<(const Node&rhs)const{ return w<rhs.w; }}node[maxm<<1];struct Edge{ int to,next,w;}edge[maxm<<1];int head[maxn],tot,p[maxn],fa[maxn],cost[maxn];int maxc[maxn][20],maxc2[maxn][20],anc[maxn][20],depth[maxn];int max1,max2;bool vis[maxm];void add(int u,int v,int w) { edge[tot].to=v,edge[tot].next=head[u],edge[tot].w=w,head[u]=tot++; }int Find(int u) { return p[u]==u?u:(p[u]=Find(p[u])); }void kruscal(){ for(int i=1;i<=n;i++) p[i]=i; mst=0,mem(vis,0),mem(head,-1),tot=0; for(int i=1;i<=m;i++){ int x=Find(node[i].u),y=Find(node[i].v); if(x!=y){ p[x]=y,mst+=node[i].w,vis[i]=1; add(node[i].u,node[i].v,node[i].w),add(node[i].v,node[i].u,node[i].w); } }}void dfs(int u,int f,int w){ cost[u]=w,fa[u]=f,depth[u]=(f==-1)?0:(depth[f]+1); for(int i=i=head[u];i!=-1;i=edge[i].next) if(edge[i].to!=f) dfs(edge[i].to,u,edge[i].w);}void process(){ for(int i=1;i<=n;i++){ anc[i][0]=fa[i],maxc[i][0]=cost[i],maxc2[i][0]=0; for(int j=1;(1<<j)<n;j++) anc[i][j]=-1; } for(int j=1;(1<<j)<n;j++) for(int i=1;i<=n;i++) if(anc[i][j-1]!=-1){ int a=anc[i][j-1]; anc[i][j]=anc[a][j-1]; maxc[i][j]=max(maxc[i][j-1],maxc[a][j-1]); if(maxc[i][j-1]==maxc[a][j-1]) maxc2[i][j]=max(maxc2[i][j-1],maxc2[a][j-1]); else if(maxc[i][j-1]>maxc[a][j-1]) maxc2[i][j]=max(maxc2[i][j-1],maxc[a][j-1]); else maxc2[i][j]=max(maxc[i][j-1],maxc2[a][j-1]); }}void cal(int u,int i){ u=anc[u][i],max1=max(max1,maxc[u][i]); if(max1==maxc[u][i]) max2=max(max2,maxc2[u][i]); else if(max1<maxc[u][i]) max2=max(max1,maxc2[u][i]); else max2=max(max2,maxc[u][i]);}void cal2(int x){ if(x>max2&&x<max1) max2=x; if(x>max1) max2=max1,max1=x;}void query(int u,int v){ if(depth[u]<depth[v]) swap(depth[u],depth[v]); int d=depth[u]-depth[v],tmp=0; for(int i=0;i<16;i++) if(d&(1<<i)) cal(u,i);//更新路径最大和严格次大值 //for(int i=16;i>=0;i--) if((tmp+=(1<<i))<=d) cal(u);//另一种写法 if(u==v) return; for(int i=16;i>=0;i--) if(anc[u][i]!=-1&&anc[u][i]!=anc[v][i]) cal(u,i),cal(v,i); cal2(cost[u]),cal2(cost[v]);}int main(){ //freopen("a.txt","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&node[i].u,&node[i].v,&node[i].w); sort(node+1,node+m+1); kruscal(); dfs(1,-1,0);//转化为有根树 process();//倍增法预处理x的第i个祖先及路径上的最长边和次长边 int ans=INF; for(int i=1;i<=m;i++){ int u=node[i].u,v=node[i].v,w=node[i].w,tmp; max1=0,max2=0; if(!vis[i]){ query(u,v);//求MST上任意两点的最长边和严格次长边 if(max1==w) tmp=mst+w-max2; else tmp=mst+w-max1; ans=min(ans,tmp); } } printf("%d\n",ans);}
0 0
- uva11354 最小瓶颈路及其应用
- uva11354 - Bond 最小瓶颈路+LCA
- UVA11354 - Bond瓶颈路
- UVA11354[Bond] 倍增求LCA+Kruskal求最小瓶颈生成树
- 最小生成树+LCA+uva11354
- 最小瓶颈路
- uva11354
- UVa 534 Frogger (最小瓶颈路)
- uva 11354 bond 最小瓶颈路
- UVA 10457 - Magic Car(最小瓶颈路)
- BZOJ 3732 Network 最小瓶颈路
- LightOJ - 1002 Country Roads(最小瓶颈路)
- 最小瓶颈路(LCA+kruskal)
- BZOJ 3732: Network 最小瓶颈路
- uva 10457 - Magic Car ( 最小瓶颈树 的应用)
- UVA 11354 Bond 瓶颈路 最小生成树+LCA类似
- UVA 544 - Heavy Cargo(最小瓶颈路)
- Frogger UVA 534(最小瓶颈路+floyd算法)
- zsim+nvmain problem to solve1
- Linux下Qt for Android 调用第三方库ZMQ
- Android界面设计
- 提高生产力和程序员价值的2种方法
- SQL查询语句拼接
- uva11354 最小瓶颈路及其应用
- 007 字符译码
- 基础练习 十六进制转八进制
- 11集合类CPtrArray和DC
- 学习
- 关于typedef的用法总结
- 杨步涛:基于用户画像的大数据挖掘实践
- geoserver中的gwc瓦片如何起作用
- mysql查询一周,一月的数据