• 矿场搭建


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

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

    我好郁闷呀。

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

    %%% 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
    ",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);
    	}
    }
    
  • 相关阅读:
    Linux基础命令—clear
    Linux基础命令—mv
    Linux基础命令—rm
    Linux基础命令—cp
    Linux基础命令—touch
    Linux基础命令—tree
    C#获取设备话筒主峰值(实时音频输出分贝量)
    C# 获取基类或者接口的所有继承类方法
    RegisterAttached 两种绑定方式
    RijndaelManaged 加密
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9230592.html
Copyright © 2020-2023  润新知