您的位置:首页 > 其它

pat 1021. Deepest Root (并查集,搜索)

2014-10-14 19:57 399 查看
此题首先想到用并查集,然后如果是树再用搜索,但是单独用dfs或bfs也是可以的

并查集注意路径压缩和按秩合并。图方面根据并查集直接能求得连通分支数。

树方面,最后的答案是首先从任意点P1出发dfs,求出最远点集合S1,再从S1中任意点P2出发,求出最远点集合S2。S1并S2即为答案。

point:N=1时可单独处理。不能用二维数组储存边,内存会不够。本身是稀疏矩阵也应当用线性存储,我这里是先排序后再存储的,可以提速。

代码:

#include<stdio.h>
#include<stack>
#include<set>
#include<map>
using namespace std;
const int MAX=10005;
int n;
int uf[MAX];
int ranka[MAX];
int link[3][MAX];
int vis[MAX];

void makeset()
{
for(int i=1;i<=n;i++)
uf[i]=i;
}

int find(int x)
{
if(x!=uf[x])
uf[x]=find(uf[x]);
return uf[x];
}

void un(int x,int y)
{

int f1 = find(x);
int f2 = find(y);
if (ranka[f1] < ranka[f2])
{
uf[f1]=f2;
}
else
if (ranka[f1] == ranka[f2])
{
uf[f1]=f2;
ranka[f2]++;
}
else
{
uf[f2]=f1;
}
}

stack<int> sta;
set<int> res;
int minnum=0;
void dfs(int start,int len)
{
sta.push(start);
if(len>minnum)
{
minnum=len;
res.clear();
res.insert(start);
}
if(len==minnum)
{
res.insert(start);
}
int i,j;
for(i=1;i<=n;i++)
{
if(link[0][i]<start)
{
if(link[1][i]==start)
{
if(!link[2][i])
{
link[2][i]=1;
dfs(link[0][i],len+1);
link[2][i]=0;
}
}
}
else
if(link[0][i]==start)
{
if(!link[2][i])
{
link[2][i]=1;
dfs(link[1][i],len+1);
link[2][i]=0;
}
}
else
break;
}
sta.pop();
}

int main()
{
scanf("%d",&n);
int x,y;
makeset();
multimap<int,int> mpp;
multimap<int,int>::iterator mp;
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
if(x<y)
mpp.insert(make_pair(x,y));
else
mpp.insert(make_pair(y,x));
un(x,y);
}
if(n==1)
{
printf("1\n");
return 0;
}
int sum=0;
for(int i2=1;i2<=n;i2++)
if(i2==uf[i2])
sum++;
if(sum>1)
printf("Error: %d components\n",sum);
else
{
int i3=1;
for(mp=mpp.begin();mp!=mpp.end();++mp,i3++)
{
link[0][i3]=mp->first;
link[1][i3]=mp->second;
}
dfs(1,0);
set<int> s2=res;
res.clear();
minnum=0;
dfs(*s2.begin(),0);
set<int>::iterator sp;
for(sp=res.begin();sp!=res.end();++sp)
s2.insert(*sp);
for(sp=s2.begin();sp!=s2.end();++sp)
printf("%d\n",*sp);
}
return 0;
}


并查集和dfs还是要写得熟练
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: