2730: [HNOI2012]矿场搭建 tarjan求割点

来源:互联网 发布:武汉java培训机构面授 编辑:程序博客网 时间:2024/04/28 16:37

又做了一道求割点的题。
可以发现,如果boom处不在割点那么是没有影响的,所以我们只讨论割点的情况。
在求出所有的割点之后,整个图被分成了几个联通块。我们对联通块含有割点的个数进行讨论。
如果无割点,那么我们只需要建立两个出口,防止建立一个出口而这个出口炸掉。
如果有一个割点,我们必须建立一个出口(不能在割点处)。
如果有两个割点,我们不需要建立出口,因为一个爆炸时我们可以从另一个出去。
所以先tarjan求割点再dfs一下每个联通块就好了。

一开始vis数组弄了bool类型然而我用的是时间戳2333333333333。

#include<iostream>#include<cstdio>#include<cstring>#define ll long longusing namespace std;int n,m,cnt,num,tot,deg,ans1,T,cases,root;ll ans2;int head[505],dfn[505],low[505],vis[505];bool cut[505];int next[1005],list[1005];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void insert(int x,int y){    next[++cnt]=head[x];    head[x]=cnt;    list[cnt]=y;}void tarjan(int x,int f){    dfn[x]=low[x]=++tot;    for (int i=head[x];i;i=next[i])        if (!dfn[list[i]])         {            tarjan(list[i],x);            low[x]=min(low[x],low[list[i]]);            if (low[list[i]]>=dfn[x])             {                if (x==root) deg++; else cut[x]=1;            }        }        else if (list[i]!=f) low[x]=min(low[x],dfn[list[i]]);}void dfs(int x){    vis[x]=T;    if (cut[x]) return;    cnt++;    for (int i=head[x];i;i=next[i])    {        if (cut[list[i]]&&vis[list[i]]!=T) num++,vis[list[i]]=T;        if (!vis[list[i]]) dfs(list[i]);    }}int main(){    m=read();    while (m)    {        memset(head,0,sizeof(head));        memset(dfn,0,sizeof(dfn));        memset(low,0,sizeof(low));        memset(cut,0,sizeof(cut));        memset(vis,0,sizeof(vis));        cnt=tot=n=ans1=T=0; ans2=1;        for (int i=1;i<=m;i++)        {            int u=read(),v=read();            n=max(n,max(u,v));            insert(u,v); insert(v,u);        }        for (int i=1;i<=n;i++)        {            if (!dfn[i]) tarjan(root=i,0);            if (deg>=2) cut[root]=1;            deg=0;        }        for (int i=1;i<=n;i++)            if (!vis[i]&&!cut[i])            {                T++; cnt=num=0;                 dfs(i);                if (!num) ans1+=2,ans2*=cnt*(cnt-1)/2;                if (num==1) ans1++,ans2*=cnt;            }        printf("Case %d: %d %lld\n",++cases,ans1,ans2);        m=read();    }    return 0;}       
0 0
原创粉丝点击