luogu题解 P2860[USACO冗余路径Redundant Paths] 缩点+桥

题目链接

https://www.luogu.org/problemnew/show/P2860

https://www.lydsy.com/JudgeOnline/problem.php?id=1718

分析

首先这题目的意思就是让任意两点之间至少有两条没有重复道路的路径,很显然,如果这个图不存在桥,就一定满足上述条件。

于是我们就是要求使这个图不存在桥需要连接的最小边数

如果把桥从图中去掉,很显然剩余的联通块中任意两点之间至少有两条没有重复道路的路径(当然也可能不是联通块而是孤立的点),对答案不会产生贡献,我们不妨就将这些联通块缩点,于是就原来的图就变成了一颗树。

然后思考题目要求,当每个节点的度为2时任意两点之间至少有两条没有重复道路的路径,因为此时任意节点都有两条不同道路可走,于是用贪心的思想我们让度数为\(1\)的先互相连接,所以计算出树中的叶节点个数\(x\),\(\lceil\frac{x}{2}\rceil\)就是答案

注意

好象没什么注意的,不过我太菜把\(edge [j] .to\)写成\(edge [i] .to\)查了好久的错

代码


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <cctype>
    #include <cmath>
    #include <map>
    #include <queue>
    #define ll long long
    #define ri register int
    using namespace std;
    const int maxn=5005;
    const int maxm=10005;
    const int inf=0x7fffffff;
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while(!isdigit(c=getchar()))ne=c==‘-‘;
        x=c-48;
        while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
        x=ne?-x:x;
        return ;
    }
    struct Edge{
        int ne,to;
    }edge[maxm<<1];
    int h[maxn],num_edge=0;
    inline void add_edge(int f,int to){
        edge[++num_edge].ne=h[f];
        edge[num_edge].to=to;
        h[f]=num_edge;
        return ;
    }
    int n,m;
    int dfn[maxn],low[maxn],tot=0;
    bool bridge[maxm];
    void tarjan(int now,int in_edge){//所在边的标号
        int v;dfn[now]=low[now]=++tot;
        for(ri i=h[now];i;i=edge[i].ne){
            v=edge[i].to;
            if(!dfn[v]){
                tarjan(v,i);
                low[now]=min(low[now],low[v]);
                if(dfn[now]<low[v]){
                   bridge[i]=bridge[i^1]=true;//是桥
                   bb++;
                }
            }
            else if(i!=(in_edge^1)){//如果不是在同一条无向边的对应边
                low[now]=min(low[now],dfn[v]);
            }
        }
        return ;
    }
    int num=0;//联通块的数量
    int in_block[maxn];//各点所在联通块的标号
    bool g[maxn][maxn];//重构后的图(储存)
    void Contraction_Point(int now){//缩点
        int v;in_block[now]=num;
        for(ri i=h[now];i;i=edge[i].ne){
           v=edge[i].to;
           if(!bridge[i]&&!in_block[v]){
               Contraction_Point(v);
           }
        }
        return ;
    }
    int du[maxn];
    inline void solve(){
        int ans=0,x,y;
        memset(g,0,sizeof(g));
        for(ri i=1;i<=n;i++){
            x=in_block[i];
            for(ri j=h[i];j;j=edge[j].ne){
                y=in_block[edge[j].to];    //太坑了
                g[x][y]=g[y][x]=1;
            }
        }
        memset(du,0,sizeof(du));
        for(ri i=1;i<=num;i++){
            for(ri j=1;j<=num;j++){
                if(i!=j&&g[i][j]){du[j]++;
                }
            }
        }
        for(ri i=1;i<=num;i++){
            if(du[i]==1)ans++;
        }
        printf("%d",(int)ceil(ans/double(2)));
        return ;
    }
    int main(){
        int x,y;
        read(n),read(m);
        num_edge=1;
        for(ri i=1;i<=m;i++){
            read(x),read(y);
            add_edge(x,y);
            add_edge(y,x);
        }
        memset(bridge,0,sizeof(bridge));
        tarjan(1,0);
        memset(in_block,0,sizeof(in_block));
        for(ri i=1;i<=n;i++){
            if(!in_block[i]){
                num++;
                Contraction_Point(i);
            }
        }
        solve();
        return 0;
    }
    

原文地址:https://www.cnblogs.com/Rye-Catcher/p/9286688.html

时间: 2024-11-05 11:56:47

luogu题解 P2860[USACO冗余路径Redundant Paths] 缩点+桥的相关文章

LUOGU P2860 [USACO06JAN]冗余路径Redundant Paths (双联通,缩点)

传送门 解题思路 刚开始是找的桥,后来发现这样不对,因为一条链就可以被卡.后来想到应该缩点后找到度数为1 的点然后两两配对. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> using namespace std; const int MAXN = 5005; const int MAXM = 10005; inline i

洛谷P2860 [USACO06JAN]冗余路径Redundant Paths

题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forced to t

[USACO06JAN]冗余路径Redundant Paths(缩点)

为了从F(1≤F≤5000)个草场中的一个走到另一个,贝茜和她的同伴们有时不得不路过一些她们讨厌的可怕的树.奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择. 每对草场之间已经有至少一条路径.给出所有R(F-1≤R≤10000)条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量, 路径由若干道路首尾相连而成.两条路径相互分离,是指两条路径没有一条重合的道路.但是,两条分离的路径上可以有一些相同的草场.

Luogu2860 [USACO06JAN]冗余路径Redundant Paths

\(\verb|Luogu2860 [USACO06JAN]冗余路径Redundant Paths|\) 给定一个连通无向图,求至少加多少条边才能使得原图变为边双连通分量 \(1\leq n\leq5000,\ n-1\leq m\leq10^4\) tarjan 边双无疑不用考虑,于是就可以边双缩点成一棵树 令现在要连的边为 \((u,\ v)\) ,点集 \(\{u->lca(u,\ v),\ v->lca(u,\ v)\}\) 将会变为一个新的点双,可以将他们看为一个新的点 可以贪心地连

冗余路径 Redundant Paths e-DCC缩点

冗余路径 Redundant Paths 题目传送 sol: 如果两点间存在至少两条不重复的路径,这说明他们两点在同一个边双连通分量(不存在割边). 那么可以进行e-DCC的缩点,得到一棵树. 对于这棵树广泛意义上的叶子节点(度数为1)而言,都还至少需要一条边连向他. 那么可以贪心的一次连两个叶子节点,答案显然就是\(cnt+1>>1\). #include<bits/stdc++.h> #define IL inline #define RG register #define D

冗余路径Redundant Paths

题意翻译 题目描述 在Byteotia有n个城镇. 一些城镇之间由无向边连接. 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些).每两个城镇之间至多只有一条直接连接的道路.人们可以从任意一个城镇直接或间接到达另一个城镇. 每个城镇都有一个公民,他们被孤独所困扰.事实证明,每个公民都想拜访其他所有公民一次(在主人所在的城镇).所以,一共会有n*(n-1)次拜访. 不幸的是,一个程序员总罢工正在进行中,那些程序员迫切要求购买某个软件. 作为抗议行动,程序员们计划封锁一些城镇,阻

[USACO06JAN]冗余路径Redundant Paths 无向图tarjan缩点

如题,缩完点后数一下有几个入度为1的scc,+1再/2即可. 教训:加一个cntf处理重边!否则重边会被认为是同一条. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 struct stack{ 9 vector<int> v;

1718: [Usaco2006 Jan] Redundant Paths 分离的路径

1718: [Usaco2006 Jan] Redundant Paths 分离的路径 Time Limit: 5 Sec  Memory Limit: 64 MB链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1718 Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to an

BZOJ 1718: [Usaco2006 Jan] Redundant Paths 分离的路径( tarjan )

tarjan求边双连通分量, 然后就是一棵树了, 可以各种乱搞... ------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 5009; struct edge { int to; b