zoukankan      html  css  js  c++  java
  • luogu题解 P2860[USACO冗余路径Redundant Paths] 缩点+桥

    题目链接

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

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

    分析

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

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

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

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

    注意

    好象没什么注意的,不过我太菜把(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;
        }
        
    
  • 相关阅读:
    逐步实现python版wc命令
    Linux中短横线(-)小记
    memcached启动脚本(class练习)
    nginx启动脚本(class练习)
    Python-类的方法
    re模块
    shutil模块
    时间模块(time/date)
    迭代器
    生成器
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9286688.html
Copyright © 2011-2022 走看看