BZOJ 2730 [HNOI2012]矿场搭建

来源:互联网 发布:facebook直播软件下载 编辑:程序博客网 时间:2024/04/30 04:56

割点。

对于每一个点,如果去掉它之后,剩下的图依然联通,那么这个点并没有什么卵用就不用考虑了。所以有用的点唯有割点!

进行缩强,可以得到一颗树。发现如果在所有叶子结点内部都建一个出口,非叶子结点内部不建,就完成了,并且不存在更优答案。

于是可以割点+缩强搞一搞,可以根据与它直接相连的割点数来判断是否是叶子结点。注意如果整张图没有割点依然有答案 2C2n

话说这题的题目描述也是够了,没有说明点序号范围,也没有说明图的连通性……

#include<cstdio>#include<cstring>#include<algorithm>#define M 505#define N 50010using namespace std;int n, ecnt;struct edge{int next,to;}e[M<<1];int last[N], dfn[N], low[N], t, belong[N], cnt[N], siz[N];bool cut[N], vis[N], point[N];void add(int a, int b){    e[++ecnt]=(edge){last[a],b};    last[a]=ecnt;}void tarjan(int x, int fa){    int tmp=0;    dfn[x]=low[x]=++t;    for(int i = last[x]; i; i=e[i].next)    {        int y=e[i].to;        if(y==fa)continue;        if(dfn[y])low[x]=min(low[x],dfn[y]);        else        {            tarjan(y,x);tmp++;            low[x]=min(low[x],low[y]);            if(dfn[x]<=low[y] && fa!=-1)cut[x]=1;        }    }    if(fa==-1 && tmp>1)cut[1]=1;}void mark(int x, int v){    belong[x]=v;    for(int i = last[x]; i; i=e[i].next)    {        int y=e[i].to;        if(cut[y] || belong[y])continue;        mark(y,v);    }}void clear(){    n=t=ecnt=0;    memset(last,0,sizeof(last));    memset(vis,0,sizeof(vis));    memset(cut,0,sizeof(cut));    memset(cnt,0,sizeof(cnt));    memset(siz,0,sizeof(siz));    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(point,0,sizeof(point));    memset(belong,0,sizeof(belong));}int main(){    int m, kase=0;    while(scanf("%d",&m),kase++,m)    {        clear();        for(int a, b, i = 1; i <= m; i++)        {            scanf("%d%d",&a,&b);            n=max(n,max(a,b));            add(a,b);            add(b,a);            point[a]=point[b]=1;        }        tarjan(1,-1);        for(int i = 1 ; i <= n; i++)            if(!belong[i] && !cut[i])                mark(i,i);        for(int i = 1; i <= n; i++)if(belong[i])siz[belong[i]]++;           for(int i = 1; i <= n; i++)        {            if(cut[i])            {                for(int j = last[i]; j; j=e[j].next)                {                    int y=e[j].to;                    if(!vis[belong[y]])                        cnt[belong[y]]++,vis[belong[y]]=1;                }                memset(vis,0,sizeof(vis));            }        }        long long ans=1,tot=0;        for(int i = 1; i <= n; i++)            if(cnt[i]==1)            {                tot++;                ans*=siz[i];            }        if(tot==0)        {            long long ans=0;            for(int i = 1; i <= n; i++)                if(point[i])                    ans++;            printf("Case %d: %d %lld\n",kase, 2, ans*(ans-1)/2);        }        else            printf("Case %d: %lld %lld\n",kase, tot, ans);    }}
1 0
原创粉丝点击