hdu2586How far away ?

来源:互联网 发布:网络棋牌游戏 编辑:程序博客网 时间:2024/04/29 00:56


就是说给你n个点,n-1条边构成一个无向图。

然后还有m次询问,每次问你两个点的最短距离。

于是转换成最短路问题?

嗯,最多有4万个点,边的话算是4万条吧,

于是用spfa的话,每次算一个单源点的最短路,

大概是32*10的8次方时间复杂度,

题目只给了1秒,

所以超时的节奏。

有一个叫做tarjan的算法,

是用来求两个节点的最近公共祖先的,

听说是正常人能写出的求此类方法的最快算法,

反正我是没看懂。

于是这道题可以转换成求最近公共祖先,

求的过程顺便算下每个点到根节点的距离就可以

求这道题了。

tarjan算法的时间渐进复杂度是询问数+图中边的数目,

于是就是8万的样子,不会超时的样子。

那么这个算法怎么写,我觉得是这样的。

它大概是用dfs和并查集实现的,

为了加快访问边的速度,我还用到了链式向前星

这个数据结构。

具体点大概是这样,

从根节点开始搜索,

每次搜索一开始就把当前搜索的那个点

标记为已经加入并查集,

加入并查集就意味着,

这个点已经加入了某棵子树,

这就意味着已经跟某个节点有了最近公共祖先,

至于某点是不是要查询的那个点就不知道了。

怎么求出要查询的两点的最近公共祖先呢?

枚举所有查询,

如果查询两个点中任意一点正好是正在搜索的

那个点,并且另一个点已经加入了某棵子树,

则把这两个点的最近公共祖先设置为此点

与某点的最近公共祖先,

至于为毛这样,不造。

然后搜索所有以这个当前搜索点的为前驱的

没有加入任何子树的后继节点,

直到所有的节点都加入了某棵子树,

这个过程就结束。

好吧,我的代码如下:

#include<iostream>#include<cstring>using namespace std;int num_dot,num_q,num_side,cnt,box[40010],dis[40010],father[40010],vis[40010];struct node{    int e,next,w;}side[80010];struct node1{    int s,e,f;}q[210];void add(int s,int e,int w){    side[cnt].e=e;    side[cnt].w=w;    side[cnt].next=box[s];    box[s]=cnt++;}void init(){    int t1,t2,t3;    cnt=0;    scanf("%d%d",&num_dot,&num_q);    num_side=num_dot-1;    memset(box,-1,sizeof(box));    memset(vis,0,sizeof(vis));    vis[1]=1;    dis[1]=0;    for(int i=0;i<num_side;i++)    {        scanf("%d%d%d",&t1,&t2,&t3);        add(t1,t2,t3);        add(t2,t1,t3);    }    for(int i=0;i<num_q;i++)        scanf("%d%d",&q[i].s,&q[i].e);}int find(int x){    while(x!=father[x])        x=father[x];    return x;}void dfs(int mid){    vis[mid]=1;    father[mid]=mid;    for(int i=0;i<num_q;i++)    {        if(q[i].s==mid&&vis[q[i].e])            q[i].f=find(q[i].e);        else if(q[i].e==mid&&vis[q[i].s])            q[i].f=find(q[i].s);    }    for(int i=box[mid];i!=-1;i=side[i].next)        if(!vis[side[i].e])        {            dis[side[i].e]=dis[mid]+side[i].w;            dfs(side[i].e);            father[side[i].e]=mid;        }}int main(){    int exp;    scanf("%d",&exp);    while(exp--)    {        init();        dfs(1);        for(int i=0;i<num_q;i++)            printf("%d\n",dis[q[i].s]+dis[q[i].e]-2*dis[q[i].f]);    }}

0 0
原创粉丝点击