1 条题解

  • 1
    @ 2023-10-29 20:04:44
    #include<bits/stdc++.h>
    using namespace std;
    const int N=110,M=1e3+5;
    const int mod=31011;
    struct node{
    	int x,y,c;
    }a[M];
    bool cmp(node n1,node n2){
    	return n1.c<n2.c;
    }
    int fa[N],siz[N];
    int get(int x){//并查集
    	if(fa[x]==x)return x;
    	return get(fa[x]);
    }
    void merge(int tx,int ty){
    	if(siz[tx]>siz[ty])swap(tx,ty);
    	fa[tx]=ty;
    	siz[ty]+=siz[tx];
    }
    int cnt,sum,l[M],r[M],c[M];
    //l数组表示当前权值相同的一段的左端点
    //r数组表示当前权值相同的一段的右端点
    //c数组表示最小生成树内当前权值的边需要多少条 
    void dfs(int pos,int now,int num){
    	if(pos==r[now]+1){
    		if(num==c[now])sum++;
    		return;
    	}
    	int x=a[pos].x,y=a[pos].y;
    	int tx=get(x),ty=get(y);
    	if(tx!=ty){
    		merge(tx,ty);
    		dfs(pos+1,now,num+1);
    		siz[ty]-=siz[tx];
    		fa[tx]=tx,fa[ty]=ty;
    		//敲重点!!!
    		//这里由于进行了回溯操作,因此实际上是一个可撤销并查集
    		//需要用一个栈来记录并查集的操作
    		//但是由于dfs本身就是栈序的,可以不需要额外开栈
    		//可撤销并查集记得不能路径压缩,不然你并查集内儿子节点部分就更新不到了
    		//不过为了保证时间复杂度,这里采用了按秩合并优化 
    	}
    	dfs(pos+1,now,num);
    }
    int main(){
    	int n,m;scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
    	}
    	sort(a+1,a+m+1,cmp);//排序 
    	for(int i=1;i<=n;i++){//初始化 
    		fa[i]=i;
    		siz[i]=1;
    	}
    	int tot=0;
    	for(int i=1;i<=m;i++){//kruskal 
    		if(a[i].c!=a[i-1].c){
    			r[cnt]=i-1;
    			l[++cnt]=i;
    		}
    		int x=a[i].x,y=a[i].y;
    		int tx=get(x),ty=get(y);
    		if(tx!=ty){
    			merge(tx,ty);
    			c[cnt]++;
    			tot++;
    		}
    	}
    	r[cnt]=m;
    	if(tot!=n-1){//不构成最小生成树,特判 
    		puts("0");
    		return 0;
    	}
    	for(int i=1;i<=n;i++){
    		fa[i]=i;
    		siz[i]=1;
    	}
    	int ans=1;
    	for(int i=1;i<=cnt;i++){
    		sum=0;
    		dfs(l[i],i,0);//搜索 
    		ans=ans*sum%mod;//乘法原理 
    		for(int j=l[i];j<=r[i];j++){//由于搜索时进行了回溯操作,因此要让并查集维持原样 
    			int x=a[j].x,y=a[j].y;
    			int tx=get(x),ty=get(y);
    			if(tx!=ty){
    				merge(tx,ty);
    			}
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    1016
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    48
    已通过
    24
    上传者