BZOJ2730: [HNOI2012]矿场搭建

来源:互联网 发布:mysql数据库索引 编辑:程序博客网 时间:2024/04/30 07:56

题目链接

【分析】

显然在割点建是不划算的。那就一定是在非割点建立出口。
接下来考虑如何最小。对于每一个点双连通分量。若其中有两个或两个以上的割点,则不需要建,因为若其中一个割点坍塌,可以通过另外一个割点进入其它连通分量中的救援出口。若只有一个割点,则只要建一个。若无割点,则需要建两个。

【代码】

#include <cstdio>#include <iostream>#include <queue>#include <vector>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#define N 1005#define M 1005#define INF 1000000000using namespace std;typedef long long ll;typedef pair<ll,ll> pa;int read(){    int x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,ind,bcc_cnt,cnt,Case;ll ans,Ans;int b[M],p[N],nextedge[M];int dfn[N],low[N],bccno[N];bool iscut[N];vector<int>bcc[N];class Edge{    public:        int x,y;};stack<Edge>st;void Add(int x,int y){    cnt++;    b[cnt]=y;    nextedge[cnt]=p[x];    p[x]=cnt;}void Anode(int x,int y){    Add(x,y);Add(y,x);}void Input_Init(){    cnt=n=ind=bcc_cnt=ans=0;Ans=1;    memset(p,0,sizeof(p));    for(int i=1;i<=m;i++)        {        static int x,y;        x=read(),y=read();        Anode(x,y);n=max(max(x,y),n);    }    for(int i=1;i<=n;i++) dfn[i]=bccno[i]=iscut[i]=0;}void Dfs(int x,int fa){    dfn[x]=low[x]=++ind;    int child=0;    for(int i=p[x];i;i=nextedge[i])    {        int v=b[i];        Edge e=(Edge){x,v};        if(!dfn[v])        {            st.push(e);            Dfs(v,x);            low[x]=min(low[x],low[v]);            child++;            if(low[v]>=dfn[x])            {                bcc_cnt++;bcc[bcc_cnt].clear();                iscut[x]=1;                for(;;)                {                    Edge k=st.top();st.pop();                    if(bccno[k.x]!=bcc_cnt)                     {                        bccno[k.x]=bcc_cnt;                        bcc[bcc_cnt].push_back(k.x);                    }                    if(bccno[k.y]!=bcc_cnt)                    {                        bccno[k.y]=bcc_cnt;                        bcc[bcc_cnt].push_back(k.y);                    }                    if(k.x==x&&k.y==v) break;                }            }        }        else if(dfn[v]<dfn[x]&&v!=fa)        {            st.push(e);            low[x]=min(low[x],dfn[v]);        }    }    if(fa<0&&child==1) iscut[x]=0;}void Get_Bcc(){    for(int i=1;i<=n;i++) if(!dfn[i])         Dfs(i,-1);}void Solve(){    for(int i=1;i<=bcc_cnt;i++)    {        int sum=0,tot=bcc[i].size();        for(int j=0;j<tot;j++)        {            int v=bcc[i][j];            if(iscut[v]) sum++;        }        if(!sum) ans+=2,Ans*=((ll)tot*(ll)(tot-1))>>1;        if(sum==1) ans++,Ans*=(ll)(tot-1);    }    printf("Case %d: %lld %lld\n",++Case,ans,Ans);}int main(){    while(1)    {        m=read();        if(!m) break;        Input_Init();        Get_Bcc();        Solve();    }    return 0;}
0 0
原创粉丝点击