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