[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 }

 

posted @ 2018-01-05 10:53  Z-Y-Y-S  阅读(458)  评论(0编辑  收藏  举报