• P2860()


    题目描述:

    为了从F(1≤F≤5000)个草场中的一个走到另一个,贝茜和她的同伴们有时不得不路过一些她们讨厌的可怕的树.奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择.

    每对草场之间已经有至少一条路径.给出所有R(F-1≤R≤10000)条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量, 路径由若干道路首尾相连而成.两条路径相互分离,是指两条路径没有一条重合的道路.但是,两条分离的路径上可以有一些相同的草场. 对于同一对草场之间,可能已经有两条不同的道路,你也可以在它们之间再建一条道路,作为另一条不同的道路.

    简单说,就是加多少条边可以让所有点都在环上(不一定是一个环)

    题解:

    边双联通:删掉一条边,图仍旧联通。于是乎:

    这不就是题面的意思吗?!

    模板题???

    于是思路非常明确:tarjan完之后硬跑即可。

    怎么硬跑呢?把所有的边双给找出来,缩成一个联通块,然后把点之间的边转化为联通块之间的边,这样,只要统计度为1的联通快,答案就get了。

    把所有已有的环给缩起来,然后再找多少入度为1的点,加边肯定是给他们两两相连,达到最优

    为什么嘞?

    首先,在度为大于1的点上加边,找到的环不是最大环,就导致原本可以一条边解决的事被分了多次解决,于是只对度为1的点,把他们两两相连,统计出的数量即为答案。

    于是,整个题目就很明朗了:

    技巧:

    1、因为是无向图,每两个点就构成了一个环,所有有一个神一般的操作:^1

    2^1=3,3^1=2;4^1=5,5^1=4....

    因为两个正反边是在一起存的,所以搜到一个边,然后用异或操作,就可以搞到下一条边得下标了,把它们都打上vis标记,就可以跑有向图了。

    坑点:

    1、因为有异或操作,所以1的话异或起来会是0,于是就跑不到了,所有cnt要初始化为1.....

    2、如果ans是奇数,在/2的过程中,可能会损失精度,所有+1/2......

    3、没了.....

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005;
    struct edge
    {
        int to,next;
    }e[maxn<<1];
    int n,m,ans;
    int head[maxn<<1],cnt=1;
    int x[maxn],y[maxn];
    inline void addedge(int from,int to)
    {
        e[++cnt].next=head[from];
        e[cnt].to=to;
        head[from]=cnt;
    }
    int dfn[maxn],low[maxn],tot,vis[maxn],top;
    int st[maxn],color[maxn],col;
    int ru[maxn];
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tot;
        st[++top]=u;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(!vis[i])
            {
                vis[i]=vis[i^1]=1;
                if(dfn[v]==0)
                {
                    tarjan(v);
                    low[u]=min(low[u],low[v]);
                }
                else
                {
                    low[u]=min(low[u],dfn[v]);
                }
            }
        }
        if(dfn[u]==low[u])
        {
            color[u]=++col;
            while(st[top]!=u)
            color[st[top]]=col,top--;
            top--;
        }        
    }
    int main()
    {
        scanf("%d%d",&n,&m);//n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x[i],&y[i]);//x[i]=read();y[i]=read();
            addedge(x[i],y[i]);
            addedge(y[i],x[i]);
        }
        
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
            tarjan(i);
        }
        
        for(int i=1;i<=m;i++)
        if(color[x[i]]!=color[y[i]])
        ru[color[x[i]]]++,ru[color[y[i]]]++;
        
        for(int i=1;i<=col;i++)
        if(ru[i]==1)
        ans++;
        
        printf("%d
    ",ans+1>>1);
        return 0;
    }

    ( zrxdl %%%)

    (完)

  • 相关阅读:
    poj 3767 I Wanna Go Home (有限制的最短路)
    gcd及扩展gcd
    2012 多校联合比赛第二场
    大整数 问题
    从数据流动看数据结构
    vc/vs常用快捷键
    函数重载
    mysql相关
    xml理解
    编译相关
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11289096.html
Copyright © 2020-2023  润新知