题目链接
1509: [NOI2003]逃学的小孩
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 732 Solved: 373
[ Submit][ Status][ Discuss]
Description
Input
第一行是两个整数N(3 N 200000)和M,分别表示居住点总数和街道总数。以下M行,每行给出一条街道的信息。第i+1行包含整数Ui、Vi、Ti(1Ui, Vi N,1 Ti 1000000000),表示街道i连接居住点Ui和Vi,并且经过街道i需花费Ti分钟。街道信息不会重复给出。
Output
仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris。
Sample Input
4 3
1 2 1
2 3 1
3 4 1
1 2 1
2 3 1
3 4 1
Sample Output
4
题解:
详细题解可以参考这篇论文。
这篇博客对题解做出了补充。
我在补充一下算法的实现,论文中提到加一些空孩子,实现的时候对于每个点都先开一个长度为4的数组,初始化长度为0,前三个是记录长度前三,第四个是用于更新的时候用的,更新时先将当前结果记录在此,然后对这个长度为4的数组进行排序更新前三长,同时更新答案即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=200000+100;
typedef long long ll;
int head[MAXN],vis[MAXN];
int tol;
ll ans;
struct Edge
{
int to,next;
ll w;
}edge[MAXN*5];
void addedge(int u,int v,int w)
{
edge[tol].to=v,edge[tol].next=head[u],edge[tol].w=w,head[u]=tol++;
edge[tol].to=u,edge[tol].next=head[v],edge[tol].w=w,head[v]=tol++;
}
struct node
{
int pos;
ll dis;
friend bool operator < (node a,node b){
return a.dis>b.dis;
}
}a[MAXN][4];
void init()
{
tol=0;
ans=0;
memset(head,-1,sizeof(head));
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
}
void dfs1(int u,int fa)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
dfs1(v,u);
a[u][3].pos=v;
a[u][3].dis=a[v][0].dis+edge[i].w;
sort(a[u],a[u]+4);
}
ans=max(ans,a[u][0].dis+2*a[u][1].dis+a[u][2].dis);
}
void dfs2(int u)
{
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v])
{
if(a[v][0].pos!=u)
a[u][3].dis=a[v][0].dis+edge[i].w;
else
a[u][3].dis=a[v][1].dis+edge[i].w;
a[u][3].pos=v;
sort(a[u],a[u]+4);
break;
}
}
ans=max(ans,a[u][0].dis+2*a[u][1].dis+a[u][2].dis);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v])
dfs2(v);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
init();
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
dfs1(1,-1);
dfs2(1);
printf("%lld\n",ans);
return 0;
}