• [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】


    题目链接:BZOJ - 1016

    题目分析

    最小生成树的两个性质:

    同一个图的最小生成树,满足:

    1)同一种权值的边的个数相等

    2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性相等

    这样,先做一次Kruscal求出每种权值的边的条数,再按照权值从小到大,对每种边进行 DFS, 求出这种权值的边有几种选法。

    最后根据乘法原理将各种边的选法数乘起来就可以了。

    特别注意:在DFS中为了在向下DFS之后消除决策影响,恢复f[]数组之前的状态,在DFS中调用的Find()函数不能路径压缩。 

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int MaxN = 100 + 5, MaxM = 1000 + 5, Mod = 31011;
    
    int n, m, Top, Sum, Cnt;
    int f[MaxN], L[MaxM], R[MaxM], Num[MaxM];
    
    typedef long long LL;
    LL Ans;
    
    struct Edge
    {
    	int u, v, w; 
    } E[MaxM];
    
    inline bool Cmp(Edge e1, Edge e2) 
    {
    	return e1.w < e2.w;
    }
    
    inline int Find(int x, int o) 
    {
    	int i, j, k;
    	j = x; 
    	while (j != f[j]) j = f[j];
    	if (o == 1) return j;
    	i = x;
    	while (i != j) 
    	{
    		k = i;
    		i = f[i];
    		f[k] = j;
    	}
    	return j;
    }
    
    void DFS(int Type, int x, int y) 
    {
    	if (x == R[Type] + 1) 
    	{
    		if (y == Num[Type]) ++Cnt;
    		return;
    	}
    	int fx, fy;
    	fx = Find(E[x].u, 1); fy = Find(E[x].v, 1);
    	if (fx != fy)
    	{
    		f[fx] = fy;
    		DFS(Type, x + 1, y + 1);
    		f[fx] = fx;
    	}
    	DFS(Type, x + 1, y);
    }
    
    int main() 
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; ++i)
    		scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
    	sort(E + 1, E + m + 1, Cmp);
    	Top = 0; Sum = 0;
    	int fx, fy;
    	for (int i = 1; i <= n; ++i) f[i] = i;
    	for (int i = 1; i <= m; ++i) 
    	{
    		if (i == 1 || E[i].w != E[i - 1].w) L[++Top] = i;
    		R[Top] = i;
    		fx = Find(E[i].u, 0); fy = Find(E[i].v, 0);
    		if (fx != fy) 
    		{
    			f[fx] = fy;
    			++Num[Top];
    			++Sum;
    		}
    	}
    	if (Sum != n - 1) 
    	{
    		printf("0
    ");
    		return 0;
    	}
    	for (int i = 1; i <= n; ++i) f[i] = i;
    	Ans = 1;
    	for (int i = 1; i <= Top; ++i) 
    	{
    		if (Num[i] == 0) continue;
    		Cnt = 0;
    		DFS(i, L[i], 0);
    		Ans = Ans * (LL)Cnt % Mod;
    		for (int j = L[i]; j <= R[i]; ++j) 
    		{
    			fx = Find(E[j].u, 0); fy = Find(E[j].v, 0);
    			if (fx != fy) f[fx] = fy;
    		}
    	}
    	printf("%d
    ", (int)Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Spring框架开发的三种模式
    IDEA 的Surround With快捷键
    Spring框架IOC和AOP的实现原理与详解
    mitmproxy 安装配置
    adb 使用
    小象代理
    requests 模块查看请求的ip地址
    smtplib 邮件模块
    淘宝直播数据爬取 + 淘宝模拟登陆
    postgresql基础操作
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4319280.html
Copyright © 2020-2023  润新知