zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:星际旅行(欧拉路)

    题目传送门(内部题4)


    输入格式

    第一行两个整数$n,m$,表示行星和虫洞的数量。
    接下来$m$行,每行两个整数$u,v$,表示存在一个双向虫洞直接连接$u$和$v$。
    每一个虫洞最多会被描述一次。


    输出格式

    一行一个整数,代表本质不用的航线的数量。


    样例

    样例输入

    5 4
    1 2
    1 3
    1 4
    1 5

    样例输出

    6


    数据范围与提示

    样例解释:
    本质不同的航线有$6$条:
    2-1-3-1-4-1-5
    2-1-3-4-5-1-4
    2-1-4-1-5-1-3
    3-1-2-1-5-1-4
    3-1-2-1-4-1-5
    4-1-2-1-3-1-5
    注意2-1-4-1-3-1-5不是另一个本质不同的航线,它与第一条航线是本质相同的。

    限制与约定:
    对于$10\%$的数据,$n,m leqslant 5$。
    对于$20\%$的数据,$n,m leqslant 10$。
    对于$40\%$的数据,$n,m leqslant 100$。
    对于$60\%$的数据,$n,m leqslant 1000$。
    对于所有的数据,$1 leqslant n,m leqslant {10}^5,1 leqslant u,v leqslant n$。


    题解

    将所有的边拆成两条,问题变成删掉两条边,使得剩下的图是一个欧拉路或者是欧拉回路。

    则分为三种情况:

      1.删掉两个自环:删掉两个自环,这两个点的度数都$-2$,成为一个欧拉回路,假设这样的点有$sum$个,则方案数为$C_{sum}^2$。

      2.删掉一个自环和一条边:删自环上面已经说明了,考虑删边,删去一条边则这两个点的度数$-1$,变为两个奇数点,成为一个欧拉路,方案数为$C_{sum}^2 imes (m-sum)$。

      3.删掉有一个公共点的两条边:该点的度数$-2$,两条边分别连接的另两个点的度数分别$-1$,成为一个欧拉路,方案数为$sum limits_{i=1}^n C_{d[i]}^2$。

    则总的方案数为:$C_{sum}^2 + C_{sum}^2 imes (m-sum) + sum limits_{i=1}^n C_{d[i]}^2$。

    至于计算过程,显然上面的方法不方便计算,那么我们考虑转化一下计算的思路。

    将情况$1$和情况$2$和起来,则第一个自环可以与剩余边结合,方案数为$m-1$,第二个自环贡献的方案数为$m-2$,根据高中课本中等差数列求和公式可得方案数为:$frac{(2 imes m-sum-1) imes sum}{2}$。

    情况3的方案数为:$frac{sum limits_{i=1}^n d[i] imes (d[i]-1)}{2}$,扫一边即可求出。

    注意图不连通的判断方式,不是点不连通,而是边不连通,可以使用并差集判断,不联通方案数为$0$。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int rd_geq[100001],rd_leq[100001],f[100001];
    long long ans,sum;
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    void connect(int x,int y){f[find(x)]=find(y);}
    int main()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)f[i]=i;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		rd_leq[x]++;//所有的度
    		rd_leq[y]++;
    		if(x==y)sum++;//统计自环
    		else
    		{
    			rd_geq[x]++;//非自环的度
    			rd_geq[y]++;
    			connect(x,y);
    		}
    	}
    	int flag=0;
    	for(int i=1;i<=n;i++)
    		if(rd_leq[i])
    		{
    			flag=i;
    			break;
    		}
    	for(int i=1;i<=n;i++)
    	{
    		if(rd_leq[i]&&find(i)!=f[flag])
    		{
    			puts("0");
    			return 0;
    		}
    		ans+=1LL*(rd_geq[i]-1)*rd_geq[i]/2;//第3种情况
    	}
    	ans+=sum*(m-sum)+sum*(sum-1)/2;//第1种和第2种情况
    	printf("%lld",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    怎么查看京东店铺的品牌ID
    PPT编辑的时候很卡,放映的时候不卡,咋回事?
    codevs 1702素数判定2
    codevs 2530大质数
    codevs 1488GangGang的烦恼
    codevs 2851 菜菜买气球
    hdu 5653 Bomber Man wants to bomb an Array
    poj 3661 Running
    poj 1651 Multiplication Puzzle
    hdu 2476 String Painter
  • 原文地址:https://www.cnblogs.com/wzc521/p/11222447.html
Copyright © 2011-2022 走看看