1. 程式人生 > >[FJOI2014]最短路徑樹問題

[FJOI2014]最短路徑樹問題

tro str ins bsp pos head desc void size

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 }

[FJOI2014]最短路徑樹問題