zoukankan      html  css  js  c++  java
  • bzoj 1016: [JSOI2008]最小生成树计数

    Description

      现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
    最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
    成树可能很多,所以你只需要输出方案数对31011的模就可以了。

    solution

    正解:kruskal+枚举
    我们需要明白:对于所有的最小生成树满足:1.相同边权的边数相同。2.相同边权的边合并的点集也是一定的.
    两个结论可以一起证明:边数显然不可能增加,不然在做第一次kruskal的时候肯定会被加入,如果边数还可以减少,那么有一些点肯定还没有被合并,那么合并可以使得边数+1.
    所以我们枚举边权,因为相同边权的边不超过10,所以对每一种边权枚举,方案相乘即可

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=10005,mod=31011;
    int fa[N],n,m,t=0;
    struct node{
    	int x,y,z;
    	bool operator <(const node &pr)const{return z<pr.z;}
    }e[N];
    inline int find(int x){return fa[x]==x?x:find(fa[x]);}
    int l[N],r[N],v[N];
    bool priwork(){
    	int x,y,cnt=0;
    	for(int i=1;i<=m;i++){
    		if(e[i].z!=e[i-1].z)t++,l[t]=i;
    		r[t]=i;
    		x=e[i].x;y=e[i].y;
    		if(find(x)==find(y))continue;
    		fa[find(y)]=find(x);
    		cnt++;v[t]++;
    	}
    	if(cnt!=n-1)return false;
    	for(int i=1;i<=n;i++)
    		for(int j=i+1;j<=n;j++)
    			if(find(i)!=find(j))return false;
    	return true;
    }
    int cnt=0;
    inline void dfs(int i,int x,int sum){
    	if(x>r[i]){if(sum==v[i])cnt++;return ;}
    	dfs(i,x+1,sum);
    	int a=find(e[x].x),b=find(e[x].y);
    	if(a!=b){
    		fa[b]=a;
    		dfs(i,x+1,sum+1);
    		fa[b]=b;fa[a]=a;
    	}
    }
    void work()
    {
    	cin>>n>>m;
    	for(int i=1;i<=m;i++)cin>>e[i].x>>e[i].y>>e[i].z;
       for(int i=1;i<=n;i++)fa[i]=i;
    	sort(e+1,e+m+1);
    	if(!priwork()){puts("0");return ;}
    	int ans=1,x,y;
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<=t;i++){
    		cnt=0;
    		dfs(i,l[i],0);
    		ans*=cnt;if(ans>=mod)ans%=mod;
    		for(int j=l[i];j<=r[i];j++){
    			x=e[j].x;y=e[j].y;
    			if(find(x)==find(y))continue;
    			fa[find(y)]=find(x);
    		}
    	}
    	cout<<ans<<endl;
    }
    
    int main()
    {
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    Swagger使用总结
    idear常用快捷键
    Liunx下安装MongoDB
    python面向对象的特点,类定义等,私有属性、公有属性、成员属性
    Python,subprocess模块(补充)
    对称加密和非对称加密概述
    Python关于导入模块的一些感想:
    Python学习第二阶段Day2,模块subprocess、 logging、re
    Python学习第二阶段Day2(json/pickle)、 shelve、xml、PyYAML、configparser、hashlib模块
    Python学习第二阶段Day2,模块time/datetime、random、os、sys、shutil
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8040130.html
Copyright © 2011-2022 走看看