图论复习P

时间:2020-05-09
本文章向大家介绍图论复习P,主要包括图论复习P使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意:n个点m条边,m-n≤20,给你q组询问,每组询问两个点之间的最短路径

分析:如果是n个点,n-1条边,显然lca就能完美解决

如果加一条边,显然需要把通过该边的路径与lca结果取最小值

但如何求通过该边的路径的最小值呢?

可以转化成通过该边两端点的路径的最小值

而通过端点的路径的最小值可以以端点跑个spfa或dij,求出其到所有节点的距离

那么从x到y经过点p的最短路径就可以表示为dis[p][x]+dis[p][y]

当然,这里需要跑spfa的点最多只有42个,也就是在树的基础上加了42条边

只需要将其取个最小值即可

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

#define ll long long

const int maxm=2e5+1;
const int maxp=3e1+1;
const int maxn=1e5+1;
const int maxlg=2e1+1;

struct Node
{
    int to,next,val;
}e[maxm<<1];
struct edge
{
    int x,y,z;
}a[maxm];
int head[maxn];
ll dis[maxp<<1][maxn];
bool vis[maxn];
int deep[maxn];
bool isp_e[maxm];
bool isp_d[maxn];
int fa[maxn][maxlg];
ll val[maxn][maxlg];
int pp[maxp<<1];
int cnt,n,m;

void add(int x,int y,int z)
{
    e[++cnt].val=z;
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}

void spfa(int x,int p)
{
    deque<int> q;q.push_back(x),dis[p][x]=0ll;
    while(!q.empty())
    {
        int now=q.front();q.pop_front();
        vis[now]=0;
        for(int i=head[now];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[p][v]>dis[p][now]+(ll)e[i].val)
            {
                dis[p][v]=dis[p][now]+(ll)e[i].val;
                if(!vis[v])
                {
                    vis[v]=1;
                    if(!q.empty()&&dis[p][v]<dis[p][q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
}

void lca()
{
    for(int i=1;i<maxlg;i++) for(int j=1;j<=n;j++)
    {
        int now=fa[j][i-1];
        fa[j][i]=fa[now][i-1];
        val[j][i]=val[j][i-1]+val[now][i-1];
    }
}

ll ask(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    int now=deep[x]-deep[y];
    ll ans=0;
    for(int i=0;now;i++,now>>=1) if(now&1) ans+=val[x][i],x=fa[x][i];
    if(x==y) return ans;
    for(int i=maxlg-1;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
        {
            ans+=val[x][i]+val[y][i];
            x=fa[x][i],y=fa[y][i];
        }
    }
    return ans+val[x][0]+val[y][0];
}

void dfs(int x,int fax)
{
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            fa[v][0]=x;
            val[v][0]=(ll)e[i].val;
            deep[v]=deep[x]+1;
            isp_e[i-1>>1]=1;
            dfs(v,x);
        }
    }
}

int main()
{
    int q,x,y,z;
    memset(dis,0x3f,sizeof(dis));
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
        a[i].x=x,a[i].y=y,a[i].z=z;
    }
    dfs(1,-1);
    memset(vis,0,sizeof(vis));
    for(int i=0;i<m;i++) if(!isp_e[i]) isp_d[a[i].x]=isp_d[a[i].y]=1;
    int pnum=0;
    for(int i=1;i<=n;i++) if(isp_d[i]) pp[++pnum]=i,spfa(i,pnum);
    lca();
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&x,&y);
        ll ans=ask(x,y);
        for(int i=1;i<=pnum;i++) ans=min(ans,dis[i][x]+dis[i][y]);
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lin4xu/p/12856678.html