[NOI2003]逃学的小孩

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_42369449/article/details/82809941

算法:最短路+树的直径

难度:NOIP

注意:多年OI一场空,不开long long见祖宗!         如果不开long long,应该会被卡到60分!

注意:dfs找树的直径时,传的参数“d”也要开long long哦!!!

  

首先,因为无论如何答案都会包括A到B的dis,所以我们先用2遍dfs找到dis(A->B)的最大值(即:树的直径);

然后我们来考虑答案的另一部分:C到A/B的最大值,既然我们已经找到了树的直径的两个端点u,v,我们只需以u,v跑两遍SPFA,找到maxn,累加到ans身上即可。

伪代码:

maxn=max(maxn,1ll*min(dis[i],diss[i]));

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <deque>
#define ll long long
#define N 200005
using namespace std;
struct node
{
	int next;
	int to;
	int val;
}edge[N<<1];
int head[N],vis[N];
ll dis[N];
int cnt=1;
void init()
{
	memset(head,-1,sizeof(head));
	cnt=1;
}
void add(int u,int v,int w)
{
	edge[cnt].next=head[u];
	edge[cnt].to=v;
	edge[cnt].val=w;
	head[u]=cnt++;
}
void spfa(int rt)
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	deque<int>Q;
	vis[rt]=1;
	dis[rt]=0;
	Q.push_front(rt);
	while(!Q.empty())
	{
		int u=Q.front();
		Q.pop_front();
		for(int i = head[u];i != -1;i = edge[i].next)
		{
			int to=edge[i].to;
			if(dis[to]>dis[u]+edge[i].val)
			{
				dis[to]=dis[u]+edge[i].val;
				if(!vis[to])
				{
					vis[to]=1;
					if(!Q.empty()&&dis[to]<dis[Q.front()])
					{
						Q.push_front(to);
					}else
					{
						Q.push_back(to);
					}
				}
			}
		}
		vis[u]=0;
	}
}
ll diss[N];
void spfaa(int rt)
{
	memset(diss,0x3f3f3f3f,sizeof(diss));
	deque<int>Q;
	vis[rt]=1;
	diss[rt]=0;
	Q.push_front(rt);
	while(!Q.empty())
	{
		int u=Q.front();
		Q.pop_front();
		for(int i = head[u];i != -1;i = edge[i].next)
		{
			int to=edge[i].to;
			if(diss[to]>diss[u]+edge[i].val)
			{
				diss[to]=diss[u]+edge[i].val;
				if(!vis[to])
				{
					vis[to]=1;
					if(!Q.empty()&&diss[to]<diss[Q.front()])
					{
						Q.push_front(to);
					}else
					{
						Q.push_back(to);
					}
				}
			}
		}
		vis[u]=0;
	}
}
ll ans;
int chan,va1,va2;
int viss[N];
void dfs(int rt,ll d)//注意开long long,否则卡40分 
{
	for(int i = head[rt];i != -1;i = edge[i].next)
	{
		int to=edge[i].to;
		if(!viss[to])
		{
			viss[to]=1;
			dis[to]=d+1ll*edge[i].val;//注意 int型加到long long上时,要进行转换!!! 
			if(dis[to]>ans)
			{
				ans=dis[to];
				chan=to;
			}
			dfs(to,dis[to]);
		}
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	init();
	for(int i = 1;i <= m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	viss[1]=1;
	dfs(1,0);
	va1=chan;
	memset(viss,0,sizeof(viss));
	viss[chan]=1;
	dfs(chan,0);
	va2=chan;
	if(va2==va1) va2=1;
	spfa(va1);
	ll maxn=0;
	spfaa(va2);
	for(int i = 1;i <= n;i++)
	{
		if(i==va1||va2==i) continue;
		if(diss[i]!=0x3f3f3f3f&&dis[i]!=0x3f3f3f3f) maxn=max(maxn,1ll*min(dis[i],diss[i]));
	}
	ans+=maxn;
	printf("%lld\n",ans);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_42369449/article/details/82809941