zoukankan      html  css  js  c++  java
  • [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;
    }
    

      

  • 相关阅读:
    springmvc中@PathVariable和@RequestParam的区别
    Spring MVC 学习总结(一)——MVC概要与环境配置
    web中session与序列化的问题
    EL表达式
    JSTL自定义标签
    [c++][语言语法]stringstream iostream ifstream
    [C++][语言语法]标准C++中的string类的用法总结
    [数据库]数据库查询语句
    [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断
    机器学习算法汇总
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4319280.html
Copyright © 2011-2022 走看看