给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路 径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他 点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。
第一行输入三个正整数n,m,K,表示有 n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci& lt;=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
求过根节点的点对:假设现在处理根节点的S子树,用f[i][0]表示前S-1棵子树中与根相距i个节点(不含根)的最长路径,f[i][1]表示方案数,类似的定义tmp为当前S子树的统计结果。一遍bfs构造出tmp,枚举该子树上的结点数更新答案,然后用tmp更新f。
1 #include<cstdio>
2 #include<vector>
3 #include<queue>
4 #include<cstring>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8
9 const int N = 30000+10;
10 const int INF = 1e9+1e9;
11
12 struct Edge {
13 int v,w;
14 Edge(int v=0,int w=0):v(v),w(w) {}
15 bool operator < (const Edge& rhs) const {
16 return v<rhs.v;
17 }
18 };
19 queue<int> q;
20 int n,m,K,root,size,d[N],inq[N];
21 int ans1,ans2,siz[N],mx[N],vis[N],dep[N],dis[N],fa[N];
22 vector<Edge> g[N],G[N];
23
24 void spfa() {
25 for(int i=2;i<=n;i++) d[i]=INF;
26 memset(inq,0,sizeof(inq));
27 inq[1]=1; q.push(1);
28 while(!q.empty()) {
29 int u=q.front(); q.pop(); inq[u]=0;
30 for(int i=0;i<g[u].size();i++) {
31 int v=g[u][i].v,w=g[u][i].w;
32 if(d[v]>d[u]+w) {
33 d[v]=d[u]+w;
34 if(!inq[v]) inq[v]=1,q.push(v);
35 }
36 }
37 }
38 }
39 void dfs(int u) {
40 vis[u]=1;
41 for(int i=0;i<g[u].size();i++) {
42 int v=g[u][i].v,w=g[u][i].w;
43 if(!vis[v] && d[v]==d[u]+w) {
44 G[u].push_back(Edge(v,w));
45 G[v].push_back(Edge(u,w));
46 dfs(v);
47 }
48 }
49 }
50 void getroot(int u) {
51 siz[u]=1; mx[u]=0;
52 for(int i=0;i<G[u].size();i++) {
53 int v=G[u][i].v;
54 if(v!=fa[u] && !vis[v]) {
55 fa[v]=u;
56 getroot(v);
57 siz[u]+=siz[v];
58 if(siz[v]>mx[u]) mx[u]=siz[v];
59 }
60 }
61 mx[u]=max(mx[u],size-siz[u]);
62 if(mx[u]<mx[root]) root=u;
63 }
64 int f[N][2],tmp[N][2];
65 void solve(int u,int S){
66 vis[u]=1; f[0][1]=1;
67 int m=G[u].size();
68 for(int i=0;i<m;i++) {
69 int v=G[u][i].v;
70 if(!vis[v]) {
71 while(!q.empty()) q.pop(); //clear
72 q.push(v),dep[v]=1,dis[v]=G[u][i].w,fa[v]=u;
73 while(!q.empty()) {
74 int now=q.front(); q.pop();
75 int k=dep[now];
76 if(k>K) break;
77 if(dis[now]>tmp[k][0])
78 tmp[k][0]=dis[now],tmp[k][1]=0;
79 if(dis[now]==tmp[k][0]) tmp[k][1]++;
80 for(int j=0;j<G[now].size();j++) {
81 int to=G[now][j].v;
82 if(!vis[to] && to!=fa[now]) {
83 fa[to]=now;
84 dep[to]=dep[now]+1;
85 dis[to]=dis[now]+G[now][j].w;
86 q.push(to);
87 }
88 }
89 }
90 //for(int j=1;j<=K;j++) printf("(%d,%d) ",tmp[j][0],tmp[j][1]);cout<<endl;
91 for(int j=1;j<=K;j++) { //tmp位于前可以取[1..K]
92 if(tmp[j][0]+f[K-j][0]>ans1)
93 ans1=tmp[j][0]+f[K-j][0],ans2=0;
94 if(tmp[j][0]+f[K-j][0]==ans1)
95 ans2+=tmp[j][1]*f[K-j][1];
96 }
97 for(int j=1;j<=K;j++) {
98 if(tmp[j][0]>f[j][0]) f[j][0]=tmp[j][0],f[j][1]=0;
99 if(tmp[j][0]==f[j][0]) f[j][1]+=tmp[j][1];
100 tmp[j][1]=tmp[j][0]=0;
101 }
102 }
103 }
104 //cout<<u<<": "<<ans1<<" "<<ans2<<endl;
105 for(int j=0;j<=K;j++) f[j][0]=f[j][1]=0;
106 m=G[u].size();
107 for(int i=0;i<m;i++) {
108 int v=G[u][i].v;
109 if(!vis[v]) {
110 size=siz[v];
111 if(siz[v]>siz[u]) siz[v]=S-siz[v];
112 root=0;
113 if(size>=K) getroot(v);
114 solve(root,siz[v]);
115 }
116 }
117 }
118 void read(int& x) {
119 char c=getchar(); int f=1; x=0;
120 while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
121 while(isdigit(c)) x=x*10+c-'0',c=getchar();
122 x*=f;
123 }
124 int main() {
125 //freopen("in.in","r",stdin);
126 //freopen("out.out","w",stdout);
127 read(n),read(m),read(K); K--;
128 int u,v,w;
129 for(int i=0;i<m;i++) {
130 read(u),read(v),read(w);
131 g[u].push_back(Edge(v,w));
132 g[v].push_back(Edge(u,w));
133 }
134 for(int i=1;i<=n;i++)
135 sort(g[i].begin(),g[i].end());
136 spfa();
137 memset(vis,0,sizeof(vis));
138 dfs(1);
139 size=n; mx[0]=INF; root=0;
140 memset(vis,0,sizeof(vis));
141 getroot(1) , solve(root,size);
142 printf("%d %d",ans1,ans2);
143 return 0;
144 }