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;
    }
    
    
  • 相关阅读:
    mysql show profiles 使用分析sql 性能
    面向对象三大特征---封装、继承、多态
    http_build_query用法,挺方便的
    请求数据
    多模匹配算法之Aho-Corasick
    php命名空间如何引入一个变量类名?
    MySQL错误:Can't connect to MySQL server (10060)
    Vim完全教程
    路由
    wireshark
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8040130.html
Copyright © 2011-2022 走看看