您的位置:首页 > 其它

bzoj1016

2014-10-13 23:05 323 查看
噗~  其实目前的想法的话 是跟着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[]
,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)
4000
);
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

;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  生成树 树结构 记数