列表

详情


NC19952. [FJOI2014]最短路径树问题

描述

给一个包含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 ≤ 10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。

输出描述

输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。

示例1

输入:

6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1

输出:

3 4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 113ms, 内存消耗: 6472K, 提交时间: 2020-11-13 13:52:21

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define pir pair<int,int>
using namespace std;
const int N=1e5+10;
vector<pir>G[N];
int n,m,mv,cnt,root,siz,K;
int s[N],froot,f[2][N],g[2][N];
bool vis[N];
int to[N<<1],nxt[N<<1],head[N],W[N<<1],totE;
#define add(a,b,c) (to[++totE]=b,nxt[totE]=head[a],W[totE]=c,head[a]=totE)
int d[N];

void dijkstra()
{
	priority_queue<pir,vector<pir>,greater<pir> >q;
	memset(d,127,sizeof d);
	q.push(make_pair(d[1]=0,1));
	int p,dis,w,v;
	while(!q.empty())
	{
		pir h=q.top();
		q.pop();
		dis=h.first;
		p=h.second;
		if(d[p]^dis)
		continue;
		sort(G[p].begin(),G[p].end());
		for(int i=0;i<G[p].size();i++)
		{
			if(d[v=G[p][i].first]>dis+(w=G[p][i].second))
			{
				q.push(make_pair(d[v]=dis+w,v));
			}
		}
	}
}
void Build(int u)
{
	int v;
	vis[u]=1;
	for(int i=0;i<G[u].size();i++)
	{
		if(!vis[v=G[u][i].first]&&d[v]==d[u]+G[u][i].second)
		{
			add(v,u,G[u][i].second);
			add(u,v,G[u][i].second);
			Build(v);
		}
	}
}
void getroot(int u,int fa)
{
	s[u]=1;
	int mx=0,v;
	for(int it=head[u];it;it=nxt[it])
	{
		if(!vis[v=to[it]]&&(v^fa))
		{
			getroot(v,u);
			s[u]+=s[v];
			if(s[v]>mx)
			mx=s[v];
		}
	}
	if(siz-mx>mx)
	mx=siz-mx;
	if(froot>mx)
	root=u,froot=mx;
}
void dfs(int u,int fa,int dep)
{
	if(dep>K)
	return;
	int v;
	if(d[u]>g[0][dep])
	g[0][dep]=d[u],g[1][dep]=0;
	if(d[u]>=g[0][dep])
	g[1][dep]++;
	for(int i=head[u];i;i=nxt[i])
	{
		if(!vis[v=to[i]]&&(v^fa))
		{
			d[v]=d[u]+W[i];
			dfs(v,u,dep+1);
		}
	}
}
void solve(int u,int S)
{
	vis[u]=1;
	f[0][0]=0;
	f[1][0]=1;
	int v;
	for(int i=head[u];i;i=nxt[i])
	{
		if(!vis[v=to[i]])
		{
			d[v]=W[i];
			dfs(v,u,1);
			for(int j=1;j<=K;j++)
			{
				if(g[0][j]+f[0][K-j]>mv)
				mv=g[0][j]+f[0][K-j],cnt=0;
				if(g[0][j]+f[0][K-j]>=mv)
				cnt+=g[1][j]*f[1][K-j]; 
			}
			for(int j=1;j<=K;j++)
			{
				if(g[0][j]>f[0][j])
				f[0][j]=g[0][j],f[1][j]=0;
				if(g[0][j]>=f[0][j])
				f[1][j]+=g[1][j];
				g[0][j]=g[1][j]=0;
			}
		}
	}
	for(int i=0;i<=K;i++)
	f[0][i]=f[1][i]=0;
	for(int i=head[u];i;i=nxt[i])
	{
		if(!vis[v=to[i]])
		{
			froot=siz=s[v];
			root=0;
			getroot(v,u);
			solve(root,s[v]);
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&K);
	--K;
	for(int a,b,c,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		G[a].push_back(make_pair(b,c));
		G[b].push_back(make_pair(a,c));
	}
	dijkstra();
	Build(1);
	memset(vis,0,sizeof vis);
	froot=siz=n;
	getroot(1,root=0);
	solve(root,n);
	printf("%d %d\n",mv,cnt);
	return 0;
}

上一题