算法:判环+树的直径
难度:NOIP
简述题意:先根据此图判环(dfs/并查集),如果有环,输出YES,exit(0);
否则,找到树的直径(2遍dfs),就可以了!
注意:1、edge数组开2倍
2、找直径时dfsd的函数中深搜要写dfsd(to,dis[to]),不要写dfs(to,dis[to]);!!!
3、整个图有可能不连通,找树的直径时要枚举n个点!
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <deque>
#define ll long long
#define N 1000005
#define M 100005
using namespace std;
struct node
{
int next;
int to;
int val;
}edge[N<<1];
int head[M],vis[M];
ll dis[M];
int viss[M];
int cnt=1,n,m;
void init()
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(viss,0,sizeof(viss));
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++;
}
bool dfs(int rt,int fa)
{
for(int i = head[rt];i != -1;i = edge[i].next)
{
int to=edge[i].to;
if(fa==to) continue;
if(vis[to]) return 1;
vis[to]=1;
dfs(to,rt);
}
return 0;
}
ll ans;
int chan;
int qwe[M];
void dfsd(int rt,ll d)
{
for(int i = head[rt];i != -1;i = edge[i].next)
{
int to=edge[i].to;
if(!viss[to])
{
dis[to]=d+1ll*edge[i].val;
viss[to]=1,qwe[to]=1;
if(ans<dis[to])
{
chan=to;
ans=dis[to];
}
dfsd(to,dis[to]);
}
}
}
ll anss;
int main ()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(qwe,0,sizeof(qwe));
int fla=0;
ans=0;
chan=0;
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);
}
for(int i = 1;i <= n;i++)
{
if(!vis[i])
{
if(dfs(i,-1))
{
puts("YES");
fla=1;
continue;
}
}
}
if(fla) continue;
int va1,va2;
for(int i = 1;i <= n;i++)
{
if(!qwe[i])
{
ans=0;
memset(dis,0,sizeof(dis));
memset(viss,0,sizeof(viss));
viss[i]=1;
qwe[i]=1;
dfsd(i,0);
va1=chan;
memset(viss,0,sizeof(viss));
viss[chan]=1;
qwe[chan]=1;
dfsd(chan,0);
va2=chan;
if(va1==va2) va2=i;
anss=max(ans,anss);
}
}
printf("%lld\n",ans);
}
return 0;
}