• LOJ-1308-Ant network(蚂蚁的网络)-求割点分隔开的子图个数及乘积


    网上的题解大都模糊,我可能写的也比较模糊吧,讲究看看。

    大致题意:

      原图没有一个割点时,特殊考虑,至少ans1=2个通风井,方案数n*(n-1)/2;

           原图上有多个割点时,每个(由割点限制成几部分的)联通块个数即为ans1;需要dfs进行vis标记和iscut区分,不重不漏;

           ans2,建设时避开在割点上建设通风井(通风井数量可最小化,以免通风井损毁后还需再建一个以备万一);求解时:当一个颜色块有两个割点时,摧毁一个蚂蚁们总可以通过另一个割点紧急转移;当一个颜色块有仅一个割点时,摧毁割点后就必须在颜色块内部建设一个。

      //五点双环一割点,(发现这个样例:颜色块为1割点不为1,用颜色块来计算就不对头了!)

      12    

      5  6  0  1  1  2  0  2  2   3   2  4   3   4

    AC题解:

    //头文件都私奔了!
    #include<set>
    using namespace std;
    #define N 10100
    #define inf 0x3f3f3f3f
    typedef unsigned long long ULL;
    int n,m,Time;   //单指向边的共m条;
    vector<int>G[N];    ///一次存贮1个内存!!
    int dfn[N],low[N];
    int color_num,in[N];
    stack<int>st;
    int father[N];
    int cas;
    int color[N];   ///表示i在的颜色块的编号,本题无用!
    bool iscut[N];      ///表示i 是否为割点
    bool vis[N];   ///dfs中有用
    int test_num;  ///dfs中从某u点(非割点)出发可以遇见的
    set<int>ss; ///从某u点(非割点)出发dfs中的遇见割点(方便去重用set)
    ULL mod;///模数
    
    void init()
    {
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        Time=0;
        color_num=0;
        memset(in,0,sizeof(in));memset(color,0,sizeof(color));
        memset(iscut,false,sizeof(iscut));
        memset(father,-1,sizeof(father));
        while(!st.empty())st.pop();
    }
    void tarjan(int u,int fa)
    {
        dfn[u]=low[u]=++Time;
        st.push(u);in[u]=1;
        father[u]=fa;   ///别忘记!
        for(int i=0;i<(int)G[u].size();i++){
            int v=G[u][i];
            if(!dfn[v]){
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
            }
            else if(v!=fa&&in[u]==1){  ///子节点在队列中并且不是父节点
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(dfn[u]==low[u]){
            ++color_num;
            int top;
            do{
                top=st.top();st.pop();
                in[top]=0;
                color[top]=color_num;   //细节!
            }while(top!=u);
        }
    }
    ULL fact_mod(ULL x){   ///对2的64次方取模(mod只有一半)
    
        while(x/(ULL)2>=mod)
            x=x-mod-mod;
        return x;
    }
    void dfs(int u)
    {
        vis[u]=1;
        test_num++;   ///从u点出发的由割点分隔开的联通图中的非割点数目
        for(int i=0;i<(int)G[u].size();i++){
            int v=G[u][i];
            if(iscut[v]){
                ss.insert(v);continue;
            }
            if(iscut[v]||vis[v])continue;   ///vis防重复,iscut防dfs到切点
            dfs(v);
        }
    }
    
    void solve()   //缩点
    {
        tarjan(0,-1);  ///单源点图,求DAG
        int ans1=0;
        ULL ans2=1;
        int rootsons=0,u,cnt=0;  ///cnt表示割点个数
        for(int i=0;i<n;i++){   ///求割点,分类特判源点0是否为割点
            if(father[i]==0)
                rootsons++;
            else{
                u=father[i]; ///父节点
                if(dfn[u]<=low[i]&&iscut[u]==false){
                    iscut[u]=true;cnt++;
                }
            }
        }
        if(rootsons>1){   ///特判源点
            iscut[0]=true;cnt++;
        }
        if(cnt==0){  ///没有割点的图
            ans1=2;
            ans2=(ULL)n*(n-1)/2;
            ans2=fact_mod(ans2);
        }
        else{
            memset(vis,false,sizeof(vis));
            for(int i=0;i<n;i++){   ///多个割点的图
                if(iscut[i]||vis[i])
                    continue;
                ss.clear();test_num=0;
                dfs(i);
                if(ss.size()<=1){
                    ans1++;ans2=ans2*(ULL)test_num;
                }
            }
        }
        ans2=fact_mod(ans2);
        printf("Case %d: %d %llu
    ",++cas,ans1,ans2);
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        cas=0;
        mod=(ULL)1;  ///求模数
        for(int i=1;i<=63;i++){
             mod=mod*(ULL)2;
        }
    
        while(T--){
            scanf("%d%d",&n,&m);
            init();
            int x,y;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&x,&y);
                G[x].push_back(y);
                G[y].push_back(x);
            }
            solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    h5 canvas
    css3选择器
    弹性盒模型
    css新增属性
    蒙版 倒影 渐变
    字符串转化为json的三种方法
    Final互评------《弹球学成语》---- 杨老师粉丝群
    Final互评------《飞词》---- 拉格朗日2018
    作业 20181204-4 互评Final版本
    换手
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/8497004.html
Copyright © 2020-2023  润新知