和我坐同桌的东神死活不让我把代码贴到他博客上- -
于是我就自己弄一个,仅此纪念我开通博客的第一篇文章。
可怜的等三天辛苦死我了。
正题开始
题目 http://acm.hdu.edu.cn/showproblem.php?pid=4514
题目大意:
设计风景线,使风景线越长越好
给定的图,如果含有环则输出“YES”,如果不含有环则输出最大的距离。
图为无向图,不会出现重复输入。所以可以放心的使用并查集判断是否存在环
当计算最大距离时,就变成了,无向无环图求最长路径。(树求直径)
图中可能不止一颗树,所以需要计算每颗树的直径,从而求出图的最长路径
计算树的直径使用两次遍历的算法
第一次以树中任意节点为根节点遍历树,求出最大距离的节点p。
第二次以p为根节点遍历树,求出最大距离,此时的最大距离就为树的直径。
#include<stdio.h>
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include<string.h>
#pragma comment(linker,"/STACK:102400000,102400000")//设置栈大小
#define MAX 100001
using namespace std;
//自定义结构体Node存放尾,和值
typedef struct Node{
int end;
int value;
}tmpNode;
//已vector 形式存放Node 定义结构体NodeList
typedef vector<Node> NodeList;
//
NodeList nodeList[MAX];
//存放孤立节点和叶子节点的结构体
typedef vector<int> LInt;
LInt starts;
int father[MAX],save[MAX],dis[MAX],vist[MAX];
int n,m;
//初始化father,save,图;
void init(){
int i;
for(i=0;i<=n;i++)
{
nodeList[i].clear();
father[i]=i;
save[i]=0;
}
//存放孤立点和叶子点的表清空
starts.clear();
}
//每次遍历之后都需要重置dis vist
void reset(){
int i;
for(i=0;i<=n;i++)
{
dis[i]=0;
vist[i]=0;
}
}
//并查集find操作,查找x的祖先,并使用save数组压缩路径
int find(int x){
int i=0,j=0;
while(x!=father[x]){
save[i++]=father[x];
x=father[x];
}
for(j=0;j<i;j++){
father[save[j]]=x;
}
return x;
}
//dfs遍历图,并计算跟节点到所有点的距离
//now存放当前节点,path为根节点到当前节点的距离
void dfs(int now,int path){
int tpath=path,i,size;
Node tmp;
size=nodeList[now].size();
for(i=0;i<size;i++){
tmp=nodeList[now][i];
if(!vist[tmp.end]){//如果节点end没有被访问过
vist[tmp.end]=1;//访问end节点
dis[tmp.end]+=path+tmp.value;//更新end节点到root的距离
path=dis[tmp.end];//更新end节点到root的距离
dfs(tmp.end,path);//遍历end的所有孩子节点
path=tpath; //重置path
vist[tmp.end]=0;//重置end的访问
}
}
}
int main(){
int flage,i,x,y,value,s1,s2;
Node node;
while(scanf("%d%d",&n,&m)!=EOF){
flage=0;//标识是否存在环
//如果m>=n则肯定存在环,只需继续输入数据
if(m>=n){flage=1;for(i=0;i<m;i++)scanf("%d%d%d",&x,&y,&value);}
else{
init();//初始化所需函数
for(i=0;i<m;i++){
scanf("%d%d%d",&x,&y,&value);
if(!flage){
s1=find(x);
s2=find(y);
if(s1==s2)flage=1;//如果s1=s2则存在环
else{
father[s1]=s2;//并查集union简化操作,此题中可以不用按秩和并
node.value=value;
node.end=y;
nodeList[x].push_back(node);//存入x到y的边
node.end=x;
nodeList[y].push_back(node);//存入y到x的边
}
}
}
}
if(flage){printf("YES\n");continue;}
int size,max,tmp,index,p,tmp1;
//如果图中在以i为起点边小于等与1,则其为叶子节点或者孤立节点
for(i=1;i<=n;i++){
if(nodeList[i].size()<=1)starts.push_back(i);
}
size=starts.size();
max=0;
for(i=1;i<=n;i++){
//如果father[i]=i,则进行dfs,此举是为了计算森林中每个树的最远路径
//通过两次dfs找到树中的最大路径。
if(father[i]==i){
reset();
vist[i]=1;//设置i为被访问
dfs(i,0);//以i为根节点dfs遍历图
tmp=0;
index=0;
for(p=0;p<size;p++){//遍历叶子节点和孤立节点找到最大的节点
tmp1=dis[starts[p]];
if(tmp1>tmp){
tmp=tmp1;index=starts[p];
}
}
//第一次遍历找到距离i最远的点index;
//以index为跟节点遍历图找到最远的点就为树中最远的路径
reset();
vist[index]=1;//设置index为被访问
dfs(index,0);//以index为跟节点遍历图
for(p=0;p<size;p++){//遍历叶子节点和孤立节点找到最大的节点
tmp1=dis[starts[p]];
if(tmp1>tmp){
tmp=tmp1;index=starts[p];
}
}
//图中每棵树中都存在一条最远路径,所以找出图中最大的路径还需要进行比较
if(tmp>max)max=tmp;
}
}
printf("%d\n",max);
}
}