bzoj1016

噗~  其实目前的想法的话 是跟着Aekdycoin神的脚步 开始坚持把bzoj继续刷下去·· 其实我并不知道自己还能坚持多久了啦不过凡事都要尽力而为  所以只是记下一些稍微重要的题目,用来作为一个类似备忘录 的作用吧!

题目的话在bzoj上面:http://www.lydsy.com/JudgeOnline/problem.php?id=1016

大概的题意就是:求一个图的最小生成树个数~


这里要用到主要的一个东西就是··~  

1、边权相等的边的个数一定。

2、做完边权为w的所有边时,图的连通性相同。

因此  可以通过这个性质先求出该图的最小生成树··~  记录下各个边权的个数,之后的话因为条件2,对边权大小进行枚举~

将求出的最小生成树中除了枚举边权以外的边全部连上~ 并查集缩点

之后从原图中找出与枚举边权相同的边~ 对于缩点之后的图进行连边~  再用一次拉普拉斯矩阵 求生成树个数就可以啦

关于拉普拉斯矩阵:http://en.wikipedia.org/wiki/Laplacian_matrix

简单地说就是 拉普拉斯矩阵=度数矩阵-邻接矩阵  对于该矩阵去掉一行一列求其行列式的值 就是生成树个数


对于每个边权都求出等价连通性的边连法  乘法定理走起~ 求出最终答案!


我只是按自己的理解来写了啦不过应该是实现方法比较挫 导致写了好长 代码风格是时候改一下啦看到人家写的2000B不到的代码各种羡慕Otz


//============================================================================
// Name        : bzoj1016.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MOD 31011
#define N 105
using namespace std;
struct node{
	int ui,vi,val;
};
node edge[2005];
int cmp(node a,node b){
	if (a.val!=b.val)
		return (a.val<b.val);
	return (a.ui<b.ui);
}
int cnt;
int fah[105];
int que[2005];
int cntq;
int getfather(int x){
	if (x!=fah[x])
		fah[x]=getfather(fah[x]);
	return (fah[x]);
}
int det(int a[][N],int n)//生成树计数:Matrix-Tree定理
{
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            a[i][j]%=MOD;
    int ret=1;
    for(int i=1; i<n; i++)
    {
        for(int j=i+1; j<n; j++)
            while(a[j][i])
            {
                int t=a[i][i]/a[j][i];
                for(int k=i; k<n; k++)
                    a[i][k]=(a[i][k]-a[j][k]*t)%MOD;
                for(int k=i; k<n; k++)
                    swap(a[i][k],a[j][k]);
                ret=-ret;
            }
        if(a[i][i]==0)
            return 0;
        ret=ret*a[i][i]%MOD;
    }
    if(ret<0)
        ret=-ret;
    return (ret+MOD)%MOD;
}
int bin_sl(int now){
	int b_l=0,b_r=cnt-1;
	while (b_r-b_l>1){
		int b_mid=(b_l+b_r)>>1;
		if (edge[b_mid].val>=now)
			b_r=b_mid;
		else
			b_l=b_mid;
	}
	if (edge[b_l].val==now) return(b_l);
	return (b_r);
}
int bin_sr(int now){
	int b_l=0,b_r=cnt-1;
	while (b_r-b_l>1){
		int b_mid=(b_l+b_r)>>1;
		if (edge[b_mid].val>now)
			b_r=b_mid;
		else
			b_l=b_mid;
	}
	if (edge[b_r].val==now) return (b_r);
	return (b_l);
}
int n,m;
int main() {
	scanf("%d%d",&n,&m);
	cnt=-1;
	for (int i=0;i<m;i++){
		cnt++;scanf("%d%d%d",&edge[cnt].ui,&edge[cnt].vi,&edge[cnt].val);
		edge[cnt].ui--;edge[cnt].vi--;
		cnt++;edge[cnt].ui=edge[cnt-1].ui;edge[cnt].vi=edge[cnt-1].vi;edge[cnt].val=edge[cnt-1].val;
	}
	cnt++;
	sort(edge,edge+cnt,cmp);
	for (int i=0;i<n;i++) fah[i]=i;
	cntq=0;
	for (int i=0;i<cnt;i++){
		int nowx,nowy;
		nowx=getfather(edge[i].ui);nowy=getfather(edge[i].vi);
		if (nowx!=nowy){
			fah[nowx]=nowy;
			que[cntq++]=i;
		}
	}
	int li,ri;
	int ans=1;
	li=ri=0;
	//cout<<cntq<<endl;
	/*for (int i=0;i<cntq;i++)
		printf("node1-->%d node2-->%d nodeval-->%d\n",edge[que[i]].ui,edge[que[i]].vi,edge[que[i]].val);
*/
	while (li<cntq){
		while (ri<cntq && edge[que[li]].val==edge[que[ri]].val) ri++;
		ri--;
		//cout<<"ri="<<ri<<endl;
		for (int i=0;i<n;i++) fah[i]=i;
		for (int i=0;i<cntq;i++)
			if (i<li || i>ri){
				int nowx,nowy;
				nowx=getfather(edge[que[i]].ui);
				nowy=getfather(edge[que[i]].vi);
				fah[nowx]=nowy;
			}
		int vised[105];
		int cntn=0;
		memset(vised,-1,sizeof(vised));
		for (int i=0;i<n;i++){
			int nowx=getfather(i);
			if (vised[nowx]==-1)
				vised[nowx]=cntn++;
		}
		int lf=bin_sl(edge[que[li]].val);
		int rf=bin_sr(edge[que[li]].val);
		int gra[N][N];
		memset(gra,0,sizeof(gra));
		for (int i=lf;i<=rf;i++){
			int nowx,nowy;
			nowx=getfather(edge[i].ui);
			nowy=getfather(edge[i].vi);
			if (nowx!=nowy){
				gra[vised[nowx]][vised[nowx]]++;gra[vised[nowy]][vised[nowy]]++;
				gra[vised[nowx]][vised[nowy]]--;gra[vised[nowy]][vised[nowx]]--;
			}
		}
		for (int i=0;i<cntn;i++){
			for (int j=0;j<cntn;j++)
				gra[i][j]/=2;
		}
		ans=ans*det(gra,cntn);
		ans%=MOD;
		ri=li=ri+1;
		//cout<<"li="<<li<<endl;
	}
	printf("%d\n",ans);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值