4016: [FJOI2014]最短路径树问题
Time Limit: 5 Sec
Memory Limit: 512 MB
Submit: 411
Solved: 136
[ Submit][ Status][ Discuss]
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的路径。
Source
[ Submit][ Status][ Discuss]
SPFA+树的点分治
苟蒻花了。。。好像很长时间(果然还是蠢)
对于点分治不再叙述,关于SPFA找最短路:
先跑一遍spfa求出从起点出发到各个点的最短距离,然后新图只留dis[i] + w == dis[j]这样的边,将他们按编号从小到大排序,最后一个dfs解决
关于犯的傻逼错误:
没考虑深度相等时的情况
数组嵌套的时候漏数组a[b[c[]]]
全局变量与局部变量使用出事
受思维定式影响代码编写准确性
点分治应该将所有被选作重心的点标号
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 3E4 + 30;
struct E{
int to,w;
};
vector <E> v1[maxn],v2[maxn];
vector <int> v3[maxn*20];
queue <int> q;
int dis[maxn],n,m,k,vis[maxn],cnt,L[maxn];
int ans1,ans2,o,Max,maxl,T[maxn],disl[maxn],father[maxn];
int siz[maxn],M,mark[maxn],head[maxn],tail[maxn],cur,cost[maxn];
bool set[maxn],USE[maxn];
void DFS(int x)
{
for (int l = 0; l < v2[x].size(); l++) {
int to = v2[x][l].to;
if (vis[to] != cnt) {
vis[to] = cnt; father[to] = x; cost[to] = v2[x][l].w;
v1[to].push_back((E){x,v2[x][l].w});
v1[x].push_back(v2[x][l]);
DFS(to);
}
}
}
void cal(int x)
{
if (L[x] == 1) M = x;
mark[x] = M;
for (int i = 0; i < v1[x].size(); i++) {
int to = v1[x][i].to;
if (USE[to] || vis[to] == cnt) continue;
int w = v1[x][i].w;
vis[to] = cnt;
dis[to] = dis[x] + w;
L[to] = L[x] + 1;
maxl = max(maxl,L[to]);
cal(to);
}
}
void DFS2(int x)
{
siz[x] = 1; v3[cur].push_back(x);
for (int i = 0; i < v1[x].size(); i++) {
int to = v1[x][i].to;
if (vis[to] == cnt || USE[to]) continue;
vis[to] = cnt; father[to] = x;
DFS2(to);
siz[x] += siz[to];
}
}
void search(int root)
{
Max = ~0U>>1;
for (int l = 0; l < v3[cur].size(); l++) {
int x = v3[cur][l];
int now = siz[root] - siz[x];
for (int i = 0; i < v1[x].size(); i++) {
int to = v1[x][i].to;
if (to == father[x] || USE[to]) continue;
now = max(now,siz[to]);
}
if (now < Max) Max = now,o = x;
}
}
bool cmp2(const int &a,const int &b)
{
if (L[a] < L[b]) return 1;
if (L[a] > L[b]) return 0;
return mark[a] < mark[b];
}
void Work()
{
head[0] = 0; tail[maxl] = v3[cur].size()-1;
for (int i = 0; i < tail[maxl]; i++) {
int A = v3[cur][i];
int B = v3[cur][i+1];
if (L[A] != L[B]) {
tail[L[A]] = i;
head[L[B]] = i+1;
}
}
for (int i = 0; i <= maxl; i++) {
int j = k-i-1;
if (j < i) break;
if (j > maxl) continue;
for (int l = head[i]; l <= tail[i]; l++) {
int A = v3[cur][l];
disl[mark[A]] = T[mark[A]] = set[mark[A]] = 0;
}
for (int l = head[j]; l <= tail[j]; l++) {
int A = v3[cur][l];
disl[mark[A]] = T[mark[A]] = set[mark[A]] = 0;
}
int ma,ti; ma = ti = 0;
for (int l = head[j]; l <= tail[j]; l++) {
int A = v3[cur][l];
if (dis[A] == ma) ++ti;
if (dis[A] > ma) {
ma = dis[A]; ti = 1;
}
set[mark[A]] = 1;
if (l < tail[j] && mark[A] != mark[v3[cur][l+1]]) {
int B = v3[cur][l+1];
disl[mark[B]] = ma;
T[mark[B]] = ti;
}
}
int ma2,ti2; ma2 = ti2 = 0;
for (int l = tail[j]; l >= head[j]; l--) {
int A = v3[cur][l];
if (dis[A] == ma2) ++ti2;
if (dis[A] > ma2) {
ma2 = dis[A]; ti2 = 1;
}
set[mark[A]] = 1;
if (l > head[j] && mark[A] != mark[v3[cur][l-1]]) {
int B = v3[cur][l-1];
if (ma2 > disl[mark[B]]) {
disl[mark[B]] = ma2;
T[mark[B]] = ti2;
}
else if (ma2 == disl[mark[B]]) T[mark[B]] += ti2;
}
}
if (ma2 > ma) ma = ma2,ti = ti2;
int A1,A2; A1 = A2 = 0;
for (int l = head[i]; l <= tail[i]; l++) {
int now = v3[cur][l];
int mar = mark[now];
int MAX,TIME;
if (!disl[mar] && !set[mar]) MAX = ma,TIME = ti;
else MAX = disl[mar],TIME = T[mar];
if (dis[now] + MAX == A1) A2 += TIME;
else if (dis[now] + MAX > A1) {
A1 = dis[now] + MAX;
A2 = TIME;
}
}
if (i == j) A2 /= 2;
if (A1 == ans1) ans2 += A2;
if (A1 > ans1) ans1 = A1,ans2 = A2;
}
}
void solve(int root)
{
++cnt;
vis[root] = cnt;
DFS2(root);
search(root);
L[o] = dis[o] = maxl = 0;
USE[o] = 1;
++cnt; vis[o] = cnt; father[o] = 0;
cal(o);
sort(v3[cur].begin(),v3[cur].end(),cmp2);
mark[v3[cur][0]] = 0;
/*for (int i = 0; i < v3[cur].size(); i++) {
int x = v3[cur][i];
int ll = L[x];
int mm = mark[x];
}*/
Work();
if (maxl*2-1 < k) return;
int O = o;
for (int i = 0; i < v1[O].size(); i++) {
int to = v1[O][i].to;
if (USE[to]) continue;
++cur;
solve(to);
}
}
bool cmp(const E &a,const E &b)
{
return a.to < b.to;
}
int getint()
{
int ret = 0;
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while ('0' <= ch && ch <= '9') {
ret = ret*10 + ch - '0';
ch = getchar();
}
return ret;
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
int x,y,z;
x = getint(); y = getint(); z = getint();
v1[x].push_back((E){y,z});
v1[y].push_back((E){x,z});
}
memset(dis,127,sizeof(dis));
dis[1] = 0;
memset(vis,0,sizeof(vis)); ++cnt;
vis[1] = cnt;
q.push(1);
while (!q.empty()) {
int K = q.front();
q.pop(); vis[K] = 0;
for (int l = 0; l < v1[K].size(); l++) {
int to = v1[K][l].to;
int w = v1[K][l].w;
if (dis[to] > dis[K] + w) {
dis[to] = dis[K] + w;
if (!vis[to]) {
vis[to] = cnt;
q.push(to);
}
}
}
}
for (int i = 1; i <= n; i++)
for (int j = 0; j < v1[i].size(); j++) {
int to = v1[i][j].to;
int w = v1[i][j].w;
if (dis[to] == dis[i] + w) v2[i].push_back(v1[i][j]);
}
for (int i = 1; i <= n; i++) sort(v2[i].begin(),v2[i].end(),cmp);
memset(vis,0,sizeof(vis));
for (int i = 1; i <= n; i++) v1[i].clear();
++cnt; vis[1] = cnt;
DFS(1);
for (int i = 1; i <= n; i++) {
int aaa = 1;
}
ans1 = ans2 = 0;
memset(USE,0,sizeof(USE));
solve(1);
printf("%d %d",ans1,ans2);
return 0;
}