大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > Java技巧 > 次小生成树Tree-LCA的位运算

次小生成树Tree-LCA的位运算

关键词:Tree-LCA次小生成树Tree-LCA的位运算  阅读(693) 赞(17)

[摘要]本文主要是对次小生成树Tree-LCA的位运算的讲解,希望对大家学习次小生成树Tree-LCA的位运算有所帮助。

  关于次小生成树 Tree-LCA的位运算我们有实例!

  小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法 等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一 个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么 需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

  Input

  第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值 为z。

  Output

  包含一行,仅一个数,表示严格次小生成树的边权和。(数 据保证必定存在严格次小生成树)

  Sample Input

  5 6

  1 2 1

  1 3 2

  2 4 3

  3 5 4

  3 4 3

  4 5 6

  Sample Output

  11

  HINT

  数据中无向图无自环;

  50% 的数据N≤2 000 M≤3 000;

  80% 的数据N≤50 000 M≤100 000;

  100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9

  。

  Source

  这题的关键就在于求Lca,记录路径上的最小与严格次小值.

  用f[i][j]表示i的第2^j个儿子(0 表示 不存在)

  那么f[i][j]=f[ f[i][ j-1] ][j-1]

  dp[i][j]和dp0[i][j]表示点i到f[i][j]的最小和严格次小值(不存在=-1),那么只需特判即可.

  [cpp]

  int lca(int x,int y,int &nowdp,int &nowdp0)

  {

  if (deep[x]<deep[y]) swap(x,y);

  int t=deep[x]-deep[y]; //差的数量

  for (int i=0;t;i++)

  if (t&bin[i]) //转化为位运算 bin[i]表示2<<i 把t看成2进制

  {

  x=f[x][i];

  t-=bin[i];

  }

 

  int i=Li-1; //Li 表示 最高存到2^(Li-1)个父亲

  while (x^y) //x和y不相等时

  {

  while (f[x][i]==f[y][i]&&i) i--; //当i==0时只能向上跳

  x=f[x][i];y=f[y][i];

  }

  }

  程序:

  [cpp]

  #include<cstdio>

  #include<cstdlib>

  #include<cstring>

  #include<iostream>

  #include<algorithm>

  #include<functional>

  using namespace std;

  #define MAXN (100000+10)

  #define MAXM (600000+10)

  #define Li (17)

  #define INF (2000000000)

  int edge[MAXM],pre[MAXM],weight[MAXM],next[MAXM],size=0;

  int addedge(int u,int v,int w)

  {

  edge[++size]=v;

  weight[size]=w;

  next[size]=pre[u];

  pre[u]=size;

  }

  int addedge2(int u,int v,int w)

  {

  addedge(u,v,w);

  addedge(v,u,w);

  }

  int f[MAXN][Li]={0},dp[MAXN][Li]={0},dp0[MAXN][Li]={0},deep[MAXN],n,m;

  struct E

  {

  int u,v,w;

  friend bool operator<(E a,E b){return a.w<b.w; }

  }e[MAXM];

  bool b[MAXM],vis[MAXN];

  int queue[MAXN],head,tail;

  void bfs()

  {

  memset(vis,0,sizeof(vis));

  head=tail=1;queue[1]=1;vis[1]=1;deep[1]=0;

  while (head<=tail)

  {

  int &u=queue[head];

  if (u!=1)

  {

  for (int i=1;i<17;i++)

  {

  if (f[u][i-1])

  {

  f[u][i]=f[f[u][i-1]][i-1];

  }

  if (f[u][i]==0) break;

  if (f[u][i])

  {

  dp[u][i]=max(dp[u][i-1],dp[f[u][i-1]][i-1]);

  }

  if (i==1)

  {

  if (dp[u][0]!=dp[f[u][0]][0]) dp0[u][1]=min(dp[u][0],dp[f[u][0]][0]);

  else dp0[u][1]=-1;

  }

  else

  {

  dp0[u][i]=max(dp0[u][i-1],dp0[f[u][i-1]][i-1]);

  if (dp[u][i-1]!=dp[f[u][i-1]][i-1]) dp0[u][i]=max(dp0[u][i],min(dp[u][i-1],dp[f[u][i-1]][i-1]));

  }

  }

  }

  for (int p=pre[u];p;p=next[p])

  {

  int &v=edge[p];

  if (!vis[v])

  {

  queue[++tail]=v;

  vis[v]=1;deep[v]=deep[u]+1;

  f[v][0]=u;dp[v][0]=weight[p];dp0[v][0]=-1;

  }

  }

  head++;

  }

  }

  int bin[Li];

  void check(int &nowdp,int &nowdp0,int c)

  {

  if (c<=nowdp0) return;

  else if (nowdp0<c&&c<nowdp) nowdp0=c;

  else if (c==nowdp) return;

  else if (nowdp<c) {nowdp0=nowdp;nowdp=c;}

  }

  int lca(int x,int y,int &nowdp,int &nowdp0)

  {

  nowdp=nowdp0=-1;

  if (deep[x]<deep[y]) swap(x,y);

  int t=deep[x]-deep[y];

  for (int i=0;t;i++)

  if (t&bin[i])

  {

  check(nowdp,nowdp0,dp[x][i]);

  check(nowdp,nowdp0,dp0[x][i]);

  x=f[x][i];

  t-=bin[i];

  }

  int i=Li-1;

  while (x^y)

  {

  while (f[x][i]==f[y][i]&&i) i--;

 

  check(nowdp,nowdp0,dp[x][i]);

  check(nowdp,nowdp0,dp0[x][i]);

  check(nowdp,nowdp0,dp[y][i]);

  check(nowdp,nowdp0,dp0[y][i]);

  x=f[x][i];y=f[y][i];

  }

  }

  int father[MAXN];

  long long sum_edge=0;

  int getfather(int x)

  {

  if (father[x]==x) return x;

  father[x]=getfather(father[x]);

  return father[x];

  }

  void union2(int x,int y)

  {

  father[father[x]]=father[father[y]];

  }

  int main()

  {

  scanf("%d%d",&n,&m);

  for (int i=1;i<=n;i++) father[i]=i;

  memset(b,0,sizeof(b));

  memset(next,0,sizeof(next));

  for (int i=0;i<Li;i++) bin[i]=1<<i;

  for (int i=1;i<=m;i++)

  {

  scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);

  }

  sort(e+1,e+1+m);

  for (int i=1;i<=m;i++)

  {

  if (getfather(e[i].u)!=getfather(e[i].v)) {union2(e[i].u,e[i].v);addedge2(e[i].u,e[i].v,e[i].w);sum_edge+=e[i].w; }

  else b[i]=1;

  }

  bfs();

  long long mindec=-1;

  for (int i=1;i<=m;i++)

  if (b[i])

  {

  int nowdp,nowdp0;

  lca(e[i].u,e[i].v,nowdp,nowdp0);

  if (nowdp==e[i].w) nowdp=nowdp0;

  if (nowdp==-1) continue;

  if (mindec==-1||mindec>e[i].w-nowdp) mindec=e[i].w-nowdp;

  }

  printf("%lld\n",sum_edge+mindec);

  return 0;

  }



相关评论