• [FJOI2014]最短路径树问题


    Description

    给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
    往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
    可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
    这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

    Input

    第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
     
     

    Output

    输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
     

    Sample Input

    6 6 4
    1 2 1
    2 3 1
    3 4 1
    2 5 1
    3 6 1
    5 6 1

    Sample Output

    3 4

    HINT

    对于所有数据n<=30000,m<=60000,2<=K<=n。
    数据保证最短路径树上至少存在一条长度为K的路径
    2016.12.7新加数据一组by - wyx-150137

    首先求字典序最小的最短路树,考虑将边拆成两条单向边,然后按终点从大到小排序,按序插入链式前向星中,保证找到的第一条最短路就是字典序最小的。

    点分就比较裸了,记深度为 $i$ 时最大的路径长度为 $sum_i$ ,长度为 $sum_i$ ,且深度为 $i$ 的路径数为 $cnt_i$ 直接转移就好了。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<queue>
      7 using namespace std;
      8 struct ZYYS
      9 {
     10   int u,v,d;
     11 }E[120001];
     12 struct Node
     13 {
     14   int next,to,d;
     15 }edge[200001];
     16 int num,head[30001],dist[30001],pre[30001],pred[30001];
     17 int size[30001],maxsize[30001],minsize,root,w[30001],k,ans,dep_max,n,m,cnt,c[300001];
     18 bool vis[30001];
     19 bool cmp(ZYYS a,ZYYS b)
     20 {
     21   if (a.u==b.u) return a.v>b.v;
     22   return a.u<b.u;
     23 }
     24 void add(int u,int v,int d)
     25 {
     26   num++;
     27   edge[num].next=head[u];
     28   head[u]=num;
     29   edge[num].to=v;
     30   edge[num].d=d;
     31 }
     32 void SPFA()
     33 {int i;
     34   queue<int>Q;
     35   memset(dist,127/2,sizeof(dist));
     36   Q.push(1);
     37   dist[1]=0;
     38   while (Q.empty()==0)
     39     {
     40       int u=Q.front();
     41       Q.pop();
     42       vis[u]=0;
     43       for (i=head[u];i;i=edge[i].next)
     44     {
     45       int v=edge[i].to;
     46       if (dist[v]>dist[u]+edge[i].d)
     47         {
     48           pre[v]=u;
     49           pred[v]=edge[i].d;
     50           dist[v]=dist[u]+edge[i].d;
     51           if (vis[v]==0)
     52         {
     53           vis[v]=1;
     54           Q.push(v);
     55         }
     56         }
     57     }
     58     }
     59 }
     60 void get_size(int x,int pa)
     61 {int i;
     62   size[x]=1;
     63   maxsize[x]=0;
     64   for (i=head[x];i;i=edge[i].next)
     65     {
     66       int v=edge[i].to;
     67       if (v==pa||vis[v]) continue;
     68       get_size(v,x);
     69       size[x]+=size[v];
     70       maxsize[x]=max(maxsize[x],size[v]);
     71     }
     72 }
     73 void get_root(int x,int pa,int r)
     74 {int i;
     75   maxsize[x]=max(size[r]-size[x],maxsize[x]);
     76   if (maxsize[x]<minsize)
     77     {
     78       minsize=maxsize[x];
     79       root=x;
     80     }
     81   for (i=head[x];i;i=edge[i].next)
     82     {
     83       int v=edge[i].to;
     84       if (v==pa||vis[v]) continue;
     85       get_root(v,x,r);
     86     }
     87 }
     88 void get_ans(int x,int pa,int dis,int dep)
     89 {int i;
     90   if (c[k-1-dep]&&w[k-1-dep]+dis==ans)
     91     cnt+=c[k-1-dep];
     92   else if (c[k-1-dep]&&ans<w[k-1-dep]+dis)
     93     ans=w[k-1-dep]+dis,cnt=c[k-1-dep];
     94   dep_max=max(dep_max,dep);
     95   for (i=head[x];i;i=edge[i].next)
     96     {
     97       int v=edge[i].to;
     98       if (v==pa||vis[v]||dep==k-1) continue;
     99       get_ans(v,x,dis+edge[i].d,dep+1);
    100     }
    101 }
    102 void get_update(int x,int pa,int dis,int dep)
    103 {int i;
    104   if (dis>w[dep]) w[dep]=dis,c[dep]=1;
    105   else if (dis==w[dep]) c[dep]++;
    106   dep_max=max(dep_max,dep);
    107   for (i=head[x];i;i=edge[i].next)
    108     {
    109       int v=edge[i].to;
    110       if (v==pa||vis[v]||dep==k-1) continue;
    111       get_update(v,x,dis+edge[i].d,dep+1);
    112     }
    113 }
    114 void slove(int x)
    115 {int i;
    116   minsize=2e9;
    117   get_size(x,0);
    118   get_root(x,0,x);
    119   vis[root]=1;
    120   dep_max=0;
    121   c[0]=1;
    122   for (i=head[root];i;i=edge[i].next)
    123     {
    124       int v=edge[i].to;
    125       if (vis[v]) continue;
    126       get_ans(v,root,edge[i].d,1);
    127       get_update(v,root,edge[i].d,1);
    128     }
    129   for (i=0;i<=dep_max;i++)
    130     w[i]=0,c[i];
    131   for (i=head[root];i;i=edge[i].next)
    132     {
    133       int v=edge[i].to;
    134       if (vis[v]==0)
    135     slove(v);
    136     }
    137 }
    138 int main()
    139 {int i,u,v,d;
    140   cin>>n>>m>>k;
    141   for (i=1;i<=m;i++)
    142     {
    143       scanf("%d%d%d",&u,&v,&d);
    144       E[2*i-1].u=u,E[2*i-1].v=v,E[2*i-1].d=d;
    145       E[2*i].u=v;E[2*i].v=u,E[2*i].d=d;
    146     }
    147   sort(E+1,E+2*m+1,cmp);
    148   for (i=1;i<=2*m;i++)
    149     {
    150       add(E[i].u,E[i].v,E[i].d);
    151     }
    152   SPFA();
    153   memset(head,0,sizeof(head));
    154   num=0;
    155   for (i=2;i<=n;i++)
    156     add(i,pre[i],pred[i]),add(pre[i],i,pred[i]);
    157   slove(1);
    158   cout<<ans<<' '<<cnt<<endl;
    159 }
  • 相关阅读:
    Java系列学习(六)-数组
    MVC系列学习(十)-生成URL与表单
    Java系列学习(五)-流程控制语句
    Java系列学习(四)-运算计算
    asp.net mvc学习笔记
    Oracle网络传输的加密和完整性验证
    mvc学习
    linq 学习
    dapper学习入门
    entity framework 学习备忘录
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8203029.html
Copyright © 2020-2023  润新知