• codeforces 652E Pursuit For Artifacts 边双连通分量


    题意:n个点,m条边的无向图,有的边上有标记,每条边只能走一次

            给你一个起点,一个终点,询问是否能找到从起点到终点的路径,这条路径至少包含一条含有标记的边

    分析:然后边双缩点

    下面介绍一下边双的性质

    1,删掉边双内任意一条边,不影响边双的连通性

    2,任取边双内两个点u,v,对于边双里面的任意一条边,至少包含于一条u到v的路径

    所以对于这个题,可以运用上述的第二个性质,对于在边双里的标记边,都是可以经过的

    然后缩点以后,变成一棵树,然后从起点所在的边双开始遍历,找到到终点所在边双的路径,询问权值是否大于0就行了

    注意一点:这里的权值是点权加边权

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <stack>
    using namespace std;
    const int N=3e5+5;
    int n,m,s,t;
    struct Edge
    {
        int u,v,w,next;
    } edge[N<<1],e[N<<1];
    int head[N],tot,h[N];
    void add(int u,int v,int w)
    {
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void adde(int u,int v,int w)
    {
        e[tot].v=v;
        e[tot].w=w;
        e[tot].next=h[u];
        h[u]=tot++;
    }
    int pre[N],low[N],clk,bcc,bel[N];
    stack<int>S;
    void targin(int u,int f)
    {
        pre[u]=low[u]=++clk;
        S.push(u);
        for(int i=head[u]; ~i; i=edge[i].next)
        {
            int v=edge[i].v;
            if(v==f)continue;
            if(!pre[v])
            {
                targin(v,u);
                low[u]=min(low[v],low[u]);
            }
            else low[u]=min(pre[v],low[u]);
        }
        if(pre[u]==low[u])
        {
            ++bcc;
            int k;
            do
            {
                k=S.top();
                S.pop();
                bel[k]=bcc;
            }
            while(k!=u);
        }
    }
    int val[N];
    bool get(int u,int f,int sum)
    {
        sum+=val[u];
        if(u==t)return sum;
        for(int i=h[u]; ~i; i=e[i].next)
        {
            int v=e[i].v;
            if(v==f)continue;
            if(get(v,u,sum+e[i].w))return true;
        }
        return false;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        int tmp=0;
        for(int i=1; i<=m; ++i)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w),tmp+=w;
            add(u,v,w),add(v,u,w);
        }
        scanf("%d%d",&s,&t);
        if(tmp==0)
        {
            printf("NO
    ");
            return 0;
        }
        targin(s,-1);
        tmp=tot;
        memset(h,-1,sizeof(h)),tot=0;
        for(int i=0; i<tmp; i=i+2)
        {
            int u=edge[i].u,v=edge[i].v;
            u=bel[u],v=bel[v];
            if(u==v)val[u]+=edge[i].w;
            else adde(u,v,edge[i].w),adde(v,u,edge[i].w);
        }
        s=bel[s];
        t=bel[t];
        if(get(s,-1,0))printf("YES
    ");
        else printf("NO
    ");
        return 0;
    }
    View Code

           

  • 相关阅读:
    C语言II博客作业01
    vscode使用相关配置
    Ubuntu配置教程
    编译原理复习
    误差与过拟合
    机器学习分类
    SQL语句使用详解
    CRC模2除法
    数据链路层之差错控制(检错编码和纠错编码)->(奇偶校验码、CRC循环冗余码、海明码)
    封装成帧、帧定界、帧同步、透明传输(字符计数法、字符串的首尾填充法、零比特填充的首尾标志法、违规编码法)
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5326435.html
Copyright © 2020-2023  润新知