zoukankan      html  css  js  c++  java
  • 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

           

  • 相关阅读:
    uva 11729 Commando War
    剑指offer 38 数字在排序数组中出现的次数
    剑指offer 35 第一个只出现一次的字符
    剑指offer 33 把数组排成最小的数
    剑指offer17 合并两个排序的链表
    跳台阶
    app上线
    剑指offer54 表示数值的字符串
    剑指offer49 把字符串转换成整数
    段错误
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5326435.html
Copyright © 2011-2022 走看看