版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}