zoukankan      html  css  js  c++  java
  • hdu 4871 树的分治+最短路记录路径

    /*
    题意:给你一些节点和一些边,求最短路径树上是k个节点的最长的路径数。
    解:1、求出最短路径树--spfa加记录
        2、树上进行操作--树的分治,分别处理子树进行补集等运算
    */
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #define ll __int64
    using namespace std;
    #define N  31000
    #define inf 10000000000000000
    ll kk;
    struct node {
    ll u,v,w,next;
    }bian[N*4];
    ll yong,head[N];
    void init() {
    yong=0;
    memset(head,-1,sizeof(head));
    }
    void addedge(ll u,ll v,ll w) {
    bian[yong].u=u;
    bian[yong].v=v;
    bian[yong].w=w;
    bian[yong].next=head[u];
    head[u]=yong++;
    }
    ll Min(ll v,ll vv) {
    return v>vv?vv:v;
    }
    ll premi[N],val[N];//用来记录前一个元素的字典序最小和前一条边的权值
    void spfa(ll u,ll n) {
      ll i,cur,dis[N],vis[N];
      queue<ll>q;
      for(i=1;i<=n;i++)
        dis[i]=inf;
        memset(vis,0,sizeof(vis));
        memset(premi,-1,sizeof(premi));
      dis[u]=0;
      q.push(u);
      while(!q.empty()) {
        cur=q.front();
        q.pop();
        vis[cur]=0;
        for(i=head[cur];i!=-1;i=bian[i].next) {
            ll v=bian[i].v;
            if(dis[v]>dis[cur]+bian[i].w) {
                dis[v]=dis[cur]+bian[i].w;
                val[v]=bian[i].w;
                premi[v]=cur;//记录前一个节点
                if(!vis[v]) {
                    vis[v]=1;
                    q.push(v);
                }
            }
            else
            if(dis[v]==dis[cur]+bian[i].w) {
                if(premi[v]==-1)premi[v]=cur;
                else
                    premi[v]=Min(premi[v],cur);
            }
        }
      }
    
      return ;
    }
    /*以下是树的分治部分*/
    ll minn,ma,num[N],nn,diss[N],len,mxx,mxnum,vis[N],ed[N];
    void dfs1(ll u,ll fa) {
    ll i;
    nn++;
    for(i=head[u];i!=-1;i=bian[i].next) {
        ll v=bian[i].v;
        if(v!=fa&&!vis[v])
            dfs1(v,u);
    }
    return ;
    }
    ll Max(ll v,ll vv) {
    return v>vv?v:vv;
    }
    void dfs2(ll u,ll fa) {
    num[u]=1;
    ll i,tit=0;
    for(i=head[u];i!=-1;i=bian[i].next) {
        ll v=bian[i].v;
        if(v!=fa&&!vis[v]) {
            dfs2(v,u);
            num[u]+=num[v];
            tit=Max(tit,num[v]);
        }
    }
    tit=Max(tit,nn-num[u]);
    if(tit<minn) {
        minn=tit;
        ma=u;
    }
    return;
    }
    void dfs4(ll u,ll fa,ll w,ll aa) {
      diss[++len]=w;
      ed[len]=aa;
      ll i;
      for(i=head[u];i!=-1;i=bian[i].next) {
        ll v=bian[i].v;
        if(v!=fa&&!vis[v])
            dfs4(v,u,w+bian[i].w,aa+1);
      }
      return;
    }
    struct nodee {//用来记录补集
     ll dis;
     ll num;
    }f[N];
    void dfs3(ll u) {
       ll i,k,j;
       if(nn<kk)return ;
        for(i=0;i<=nn;i++)
            f[i].dis=0,f[i].num=0;
       for(i=head[u];i!=-1;i=bian[i].next) {
        ll v=bian[i].v;
        if(vis[v])continue;
        len=0;
      //  printf("v=%I64d w=%I64d
    ",v,bian[i].w);
        dfs4(v,-1,bian[i].w,1);//因为这里实际是两个节点但是要把它看成一个节点
      //  printf("len=%I64d
    ",len);
        for(j=1;j<=len;j++) {
            //    printf("z%I64d %I64d %I64d
    ",j,ed[j],diss[j]);
        if(ed[j]+1==kk) {//和当前子树比较
                if(diss[j]>mxx) {
                        mxx=diss[j];
                        mxnum=1;
                    }
                    else
                        if(diss[j]==mxx)
                        mxnum++;
                }
                if(kk-ed[j]-1<=0)continue;
            k=diss[j]+f[kk-ed[j]].dis;//补集
          //  printf("khe=%I64d
    ",k);
            if(k>mxx) {
                mxx=k;
               mxnum=f[kk-ed[j]].num;
            }
            else
            if(k==mxx)
             mxnum+=f[kk-ed[j]].num;
        }
        for(j=1;j<=len;j++) {//加入补集
            if(ed[j]+1>=kk)continue;
              if(f[ed[j]+1].dis<diss[j]) {//节点数要加一加入
                f[ed[j]+1].dis=diss[j];
                f[ed[j]+1].num=1;
              }
              else if(f[ed[j]+1].dis==diss[j])
                f[ed[j]+1].num++;
        }
       }
       //printf("%I64d %I64d
    ",mxx,mxnum);
       return ;
    }
    void dfs(ll u) {
      minn=inf;
      nn=0;
      dfs1(u,-1);
      dfs2(u,-1);
      //printf("minn=%I64d %I64d
    ",minn,ma);
      vis[ma]=1;
      dfs3(ma);
      ll i;
      for(i=head[ma];i!=-1;i=bian[i].next) {
        ll v=bian[i].v;
        if(!vis[v])
            dfs(v);
      }
      return;
    }
    int main() {
       ll t,n,m,i,j,k;
       scanf("%I64d",&t);
       while(t--) {
        init();
        scanf("%I64d%I64d%I64d",&n,&m,&kk);
        while(m--) {
            scanf("%I64d%I64d%I64d",&i,&j,&k);
            addedge(i,j,k);
            addedge(j,i,k);
        }
        if(kk==1) {//是1的时候特殊处理
            printf("0 %I64d
    ",n);
            continue;
        }
        spfa(1,n);//求最短路
        //prllf("z");
        init();
        for(i=2;i<=n;i++) {//建立最短路径树
            addedge(i,premi[i],val[i]);
            addedge(premi[i],i,val[i]);
        }
      // for(i=0;i<yong;i++)
      //      printf("%I64d %I64d %I64d
    ",bian[i].u,bian[i].v,bian[i].w);
        memset(vis,0,sizeof(vis));
        mxx=-1;mxnum=0;//用来记录最长值和路径数
        dfs(1);
        printf("%I64d %I64d
    ",mxx,mxnum);
       }
    return 0;}
    

  • 相关阅读:
    Python 基础之 线程与进程
    python 基础之 模块
    Python 基础之socket编程(三)
    Python 基础之socket编程(二)
    Python全栈开发之11、进程和线程
    用 Python实现一个ftp+CRT(不用ftplib)
    Python全栈开发之10、网络编程
    Python全栈开发之9、面向对象、元类以及单例
    Python全栈开发之8、装饰器详解
    用python实现一个无界面的2048
  • 原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410589.html
Copyright © 2011-2022 走看看