bzoj2730/UVALIVE5135 矿场搭建 求割点

来源:互联网 发布:运动减肥软件下载 编辑:程序博客网 时间:2024/04/30 06:44

前(sai)记(hua)

第一次见到这道题是在某大佬的博客里(那时它还叫UVALIVE5135),以为它是点双连通的裸题(然而我最后没有用点双),没调出来,未果。
在班上大佬讲课时又遇见它【然后它变成了bzoj的题?】了,调出来了

解法

在一个连通图有多个连通分量时

该连通图矿井个数为割点为1的连通图的个数。
方案数为割点为1的连通图的点数-1(割点)相乘

在一个连通图只有一个连通分量时

该连通图的矿井个数为2
方案数为c(2,总点数)

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=5e4+5,M=5e4+5;bool iscut[N],vis[N];int low[N],dfn[N],idc;int head[N],nxt[M],to[M],etot;int u[N],v[N],c[N],cut[N],tot; void adde(int u,int v){    to[++etot]=v;    nxt[etot]=head[u];    head[u]=etot;}void tarjan(int u,int fa){    int son=0;    low[u]=dfn[u]=++idc;    for(int i=head[u];i;i=nxt[i]){        int v=to[i];        if(v==fa) continue;        if(!dfn[v]){            son++;            tarjan(v,u);            low[u]=min(low[v],low[u]);            if(low[v]>=dfn[u]) iscut[u]=1;        }           else low[u]=min(low[u],dfn[v]);     }    if(u==fa&&son<=1) iscut[u]=0;  }int cnt;int dfs(int u,int sta){    int ans=0;    vis[u]=1;cnt++;    for(int i=head[u];i;i=nxt[i]){        int v=to[i];        if(vis[v]) continue;        if(iscut[v]){            if(cut[v]!=sta) {cut[v]=sta;ans++;}            continue;        }        ans+=dfs(v,sta);    }    return ans;}void init(){    etot=0;idc=0;tot=0;    memset(vis,0,sizeof(vis));    memset(head,0,sizeof(head));    memset(low,0,sizeof(low));    memset(dfn,0,sizeof(dfn));    memset(iscut,0,sizeof(iscut));    memset(cut,0,sizeof(cut));}int main(){    int n,k=0;    while(scanf("%d",&n)&&n){        k++;        init();        for(int i=1;i<=n;i++){            scanf("%d%d",&u[i],&v[i]);            c[++tot]=u[i],c[++tot]=v[i];        }        sort(c+1,c+1+n*2);        int sum=unique(c+1,c+1+n*2)-c-1;        for(int i=1;i<=n;i++){            u[i]=lower_bound(c+1,c+1+sum,u[i])-c;            v[i]=lower_bound(c+1,c+1+sum,v[i])-c;            adde(u[i],v[i]);            adde(v[i],u[i]);        }        tarjan(1,1);        int exit=0;long long ans=1;        for(int i=1;i<=sum;i++)        if(!vis[i]&&!iscut[i]){            cnt=0;            int x=dfs(i,i);            if(x==1) {                exit++;                ans=(long long)ans*cnt;            }            if(!x){                exit+=2;                ans=(long long)ans*cnt*(cnt-1)/2;             }          }        printf("Case %d: %d %lld\n",k,exit,ans);            //bzoj要改成lld?     }    return 0;} 
阅读全文
0 0
原创粉丝点击