• Luogu_P3225 [HNOI2012]矿场搭建 割点


    Luogu_P3225 [HNOI2012]矿场搭建

    割点


    题目链接
    这种把点拿走明显就和割点有关系
    那么就先求割点
    求完割点然后???
    首先dfs每个割点分开的连通块
    如果这个连通块没有割点,必然要两个出口
    假如有这个联通有一个割点那么一定要放一个,因为假如割点塌了就需要这个点了
    假如有两个或者更多那么就不需要了,因为哪怕塌了割点也可以从别的割点走


    代码如下:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1010;
    int tim,n,m,head[maxn],tot,cnt,low[maxn],dfn[maxn],cut[maxn],rt,vis[maxn],cct,siz,cs;
    struct node{
        int nxt,to;
        #define nxt(x) e[x].nxt
        #define to(x) e[x].to
    }e[maxn<<1];
    inline void add(int from,int to){
        to(++tot)=to;nxt(tot)=head[from];head[from]=tot;
    }
    void tarjan(int x){
        dfn[x]=low[x]=++cnt;
        int fl=0;
        for(int i=head[x];i;i=nxt(i)){
            int y=to(i);
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(low[y]>=dfn[x]){
                    fl++;
                    if(x!=rt || fl>1) cut[x]=1;
                }
            }else low[x]=min(low[x],dfn[y]);
        }
    }
    void dfs(int x){
        vis[x]=tim;
        if(cut[x]) return;
        siz++;
        for(int i=head[x];i;i=nxt(i)){
            int y=to(i);
            if(cut[y] && vis[y]!=tim) cct++,vis[y]=tim;
            if(!vis[y]) dfs(y);
        }
    }
    int main()
    {
        while(scanf("%d",&m) && m){
            memset(head,0,sizeof(head));memset(e,0,sizeof(e));siz=tim=cnt=n=tot=cct=0;
            memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(cut,0,sizeof(cut));memset(vis,0,sizeof(vis));
            for(int x,y,i=1;i<=m;i++){
                scanf("%d%d",&x,&y);add(x,y);add(y,x);n=max(n,y);n=max(n,x);
            }
            for(int i=1;i<=n;i++) if(!dfn[i]) rt=i,tarjan(i);
            ll ans1=0,ans2=1;
            for(int i=1;i<=n;i++)
                if(!vis[i] && !cut[i]){
                    tim++;cct=siz=0;
                    dfs(i);
                    if(!cct)
                        ans1+=2,ans2*=siz*(siz-1)/2;
                    if(cct==1)
                        ans1++,ans2*=siz;
                }
            printf("Case %d: %lld %lld
    ",++cs,ans1,ans2);
        }
        return 0;
    }
    
  • 相关阅读:
    数组初始化 和 vector初始化
    剑指offer42 左旋转字符串
    k sum(lintcode)
    背包问题2 (lintcode)
    92.背包问题(lintcode)
    72. Edit Distance
    79 最长公共子串 (lintcode)
    77 最长公共子序列 (lintcode)
    132. Palindrome Partitioning II
    Mysql经常使用函数汇总
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11652712.html
Copyright © 2020-2023  润新知