矿场搭建

今天我这一台机器好像不知道怎么回事,好像被限速了似的。贼慢

今天晚上还有可能回去上万恶的文化课

我好郁闷呀。

不过今天也终于将点双和边双彻底理解了

%%% tarjan

题目入口

一开始没有考虑割点能存在于不同的点双中。

考虑到了以后又在纠结如何计数233

结果发现竟然是最简单的乘法原理233

割点数量 \(0\) \(1\) \(>=2\)
方案数 \(C^2_n\) \(n-1\) \[0\]

什么意思呢,当一个点双中没有割点时,那么放哪都可以,不过要放两个。如果只放一个的话,如果碰巧就是这个塌了。那就GG了

当点双中只有一个割点时,那么放在这个点双的任意一个位置就行了。如果割点被GG了。我们有在点双中的逃生出口。如果点双中的逃生出口GG了。我们就可以通过割点溜之大吉。

如果有两个及以上的割点。因为只会塌方一个,所以无论怎么塌,都可以转移到其他的点双中。就不用再建立了。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
int m,n;
int dfn[510],low[510];
int g_num;
vector<int>g[510];
vector<int>l[510];
int t,root;
bool p[510];
int stack[510],top;
void tarjan(int now)
{
    dfn[now]=low[now]=++t;
    stack[++top]=now;
    int chi=0;
    for(int i=0;i<l[now].size();i++)
    {
        int nxt=l[now][i];
        if(!dfn[nxt])
        {
            chi+=1;
            tarjan(nxt);
            low[now]=min(low[now],low[nxt]);
            if((now==root&&chi>1)||(now!=root&&dfn[now]<=low[nxt])) 
                p[now]=true;
            if(low[nxt]>=dfn[now])
            {
                int pas;
                g_num+=1;
                do
                {
                    pas=stack[top--];
                    g[g_num].push_back(pas);
                }while(pas!=nxt);
                g[g_num].push_back(now);
            }
        }
        else    low[now]=min(dfn[nxt],low[now]);
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
        g[i].clear(),p[i]=false,l[i].clear(),dfn[i]=0,low[i]=0;
    n=0;
    t=0;g_num=0;
    int a,b;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        l[b].push_back(a);
        l[a].push_back(b);
        a=max(a,b);
        n=max(a,n);
    }
    long long set=0,way=1;
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            root=i,tarjan(i);
    for(int i=1;i<=g_num;i++)
    {
        int cut=0;
        for(int j=0;j<g[i].size();j++)
            if(p[g[i][j]])  cut+=1;
        int tot=g[i].size();
        if(!cut)    set+=2ll,way*=1ll*(tot-1)*tot/2;
        if(cut==1)  set+=1ll,way*=1ll*(tot-1);
    }
    //printf("%lld %lld\n",set,way);
    cout<<set<<" "<<way<<endl;
}
int main()
{
    freopen("input.in","r",stdin);
    freopen("input.out","w",stdout);
    scanf("%d",&m);
    int tot=0;
    while(m)
    {
        printf("Case %d: ",++tot);
        solve();
        scanf("%d",&m);
    }
}

猜你喜欢

转载自www.cnblogs.com/Lance1ot/p/9230592.html
今日推荐