题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016

就是缩点,每次相同权值的边构成的联通块求一下matrix tree。注意gauss里的编号应该是从1到...的连续的。

学习了一个TJ。用了vector。自己曾写过一个只能过样例的。都放上来吧。

路径压缩的话会慢?循环里ed[i].w!=ed[i+1].w的话会慢?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=,M=,mod=;
int n,m,fa[N],pa[N],c[N][N],a[N][N],ans=;//ans=1
bool vis[N];
vector<int> v[N];
struct Ed{
int x,y,w;
bool operator< (const Ed &b)const
{return w<b.w;}
}ed[M];
int find(int a,int f[]){return f[a]==a?a:find(f[a],f);} //加上路径压缩会变慢!!!
int gauss(int n)
{
bool fx=;int ret=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)a[i][j]%=mod;//
for(int i=;i<=n;i++)
{
int k=i;
for(int j=i+;j<=n;j++)if(abs(a[j][i])>abs(a[k][i]))k=j;
if(k!=i)
{
fx=!fx;for(int j=i;j<=n;j++)swap(a[i][j],a[k][j]);
}
for(int j=i+;j<=n;j++)
while(a[j][i])
{
fx=!fx;int tmp=a[i][i]/a[j][i];
for(int l=i;l<=n;l++)
{
int tp=a[i][l];a[i][l]=a[j][l];//i=j
a[j][l]=(tp-tmp*a[j][l])%mod;//j=i%j
}
}
(ret*=a[i][i])%=mod;
}
return (ret*(fx?-:)+mod)%mod;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)fa[i]=i,pa[i]=i;
for(int i=;i<=m;i++)
scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].w);
sort(ed+,ed+m+);
for(int i=;i<=m+;i++)//
{ if(ed[i-].w!=ed[i].w||i==m+)//
{
for(int j=;j<=n;j++)
{
if(!vis[j])continue;
v[find(j,pa)].push_back(j);
vis[j]=;
}
for(int j=;j<=n;j++)
{
if(v[j].size()<=)continue;
memset(a,,sizeof a);//!
int siz=v[j].size();
for(int l0=;l0<siz;l0++)
for(int l1=l0+;l1<siz;l1++)
{
int x=v[j][l0],y=v[j][l1],t=c[x][y];//x=v[j][l0],don't use l0 directly
a[l0+][l0+]+=t;a[l1+][l1+]+=t;
a[l0+][l1+]-=t;a[l1+][l0+]-=t;//but here is l0/1, for in gauss the bh must from 1 and be continous
}
(ans*=gauss(siz-))%=mod;
for(int k=;k<siz;k++)fa[v[j][k]]=j;//fa -> pa
}
for(int j=;j<=n;j++)
{
fa[j]=pa[j]=find(j,fa);v[j].clear();
}
}
int f1=find(ed[i].x,fa),f2=find(ed[i].y,fa);
if(f1==f2)continue;vis[f1]=;vis[f2]=;
pa[find(f1,pa)]=find(f2,pa);c[f1][f2]++;c[f2][f1]++;
}
for(int i=;i<n;i++)if(find(i,fa)!=find(i+,fa)){printf("");return ;}
printf("%d",ans);
return ;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=,M=,mod=;
int n,m,fa[N],pa[N],c[N][N],a[N][N],ans=;//ans=1
bool vis[N];
vector<int> v[N];
struct Ed{
int x,y,w;
bool operator< (const Ed &b)const
{return w<b.w;}
}ed[M];
int find(int a,int f[]){return f[a]==a?a:find(f[a],f);} //加上路径压缩会变慢!!!
int gauss(int n)
{
bool fx=;int ret=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)a[i][j]%=mod;//
for(int i=;i<=n;i++)
{
int k=i;
for(int j=i+;j<=n;j++)if(abs(a[j][i])>abs(a[k][i]))k=j;
if(k!=i)
{
fx=!fx;for(int j=i;j<=n;j++)swap(a[i][j],a[k][j]);
}
for(int j=i+;j<=n;j++)
while(a[j][i])
{
fx=!fx;int tmp=a[i][i]/a[j][i];
for(int l=i;l<=n;l++)
{
int tp=a[i][l];a[i][l]=a[j][l];//i=j
a[j][l]=(tp-tmp*a[j][l])%mod;//j=i%j
}
}
(ret*=a[i][i])%=mod;
}
return (ret*(fx?-:)+mod)%mod;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)fa[i]=i,pa[i]=i;
for(int i=;i<=m;i++)
scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].w);
sort(ed+,ed+m+);
for(int i=;i<=m;i++)
{
int f1=find(ed[i].x,fa),f2=find(ed[i].y,fa);
if(f1!=f2){
vis[f1]=;vis[f2]=;
pa[find(f1,pa)]=find(f2,pa);c[f1][f2]++;c[f2][f1]++;
}
// if(f1==f2)continue;//!!!!!!!
if(ed[i+].w!=ed[i].w||i==m)
{
for(int j=;j<=n;j++)
{
if(!vis[j])continue;
v[find(j,pa)].push_back(j);
vis[j]=;
}
for(int j=;j<=n;j++)
{
if(v[j].size()<=)continue;
memset(a,,sizeof a);//!
int siz=v[j].size();
for(int l0=;l0<siz;l0++)
for(int l1=l0+;l1<siz;l1++)
{
int x=v[j][l0],y=v[j][l1],t=c[x][y];//x=v[j][l0],don't use l0 directly
a[l0+][l0+]+=t;a[l1+][l1+]+=t;
a[l0+][l1+]-=t;a[l1+][l0+]-=t;//but here is l0/1, for in gauss the bh must from 1 and be continous
}
(ans*=gauss(siz-))%=mod;
for(int k=;k<siz;k++)fa[v[j][k]]=j;//fa -> pa
}
for(int j=;j<=n;j++)
{
fa[j]=pa[j]=find(j,fa);v[j].clear();
}
}
}
for(int i=;i<n;i++)if(find(i,fa)!=find(i+,fa)){printf("");return ;}
printf("%d",ans);
return ;
}

改一下循环(慢?)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=,mod=;
int n,m,p0,p1,col[N],cnt,head[N],xnt,fnw,ans=,fa[N],bh[N],tot;
bool used[M<<],vis[N],nd[N],tvis[N];
struct Ed{
int next,x,y,w;
Ed(int x=,int y=,int w=):x(x),y(y),w(w) {}
bool operator< (const Ed &b)const
{return w<b.w;}
}ed[M<<];
struct Matrix{
int a[N][N];
void init(){memset(a,,sizeof a);}
Matrix operator- (const Matrix &b)const
{
Matrix c;c.init();
for(int i=;i<tot;i++)
for(int j=;j<tot;j++)
c.a[i][j]=(a[i][j]-b.a[i][j])%mod;//
return c;
}
}d,l,r;
int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
void add(int x,int y,int w)
{
ed[++xnt]=Ed(x,y,w);
ed[++xnt]=Ed(y,x,w);
if(find(x)!=find(y))fa[find(x)]=find(y);
}
void dfst(int cr)
{
tvis[cr]=;bh[cr]=++tot;
for(int i=head[cr],v;i;i=ed[i].next)
if(used[i]&&!tvis[ed[i].y])dfst(ed[i].y);
}
void dfsx(int cr,int f) //dfs处理好这一块的度数矩阵和邻接矩阵
{
vis[cr]=;
for(int i=head[cr],v;i;i=ed[i].next)
if(used[i]&&(v=ed[i].y)!=f)
{
d.a[bh[cr]][bh[cr]]++;if(!vis[v])d.a[bh[v]][bh[v]]++;
l.a[bh[cr]][bh[v]]=l.a[bh[v]][bh[cr]]=;
if(!vis[v])dfsx(v,cr);
}
}
void gauss()
{
int fx=,ret=;
for(int i=;i<tot;i++)//<tot,少一行一列
{
int nw=i;
for(int j=i+;j<tot;j++)if(abs(r.a[j][i])>abs(r.a[nw][i]))nw=j;
if(nw!=i)
{
fx=-fx;for(int l=i;l<tot;l++)swap(r.a[i][l],r.a[nw][l]);
}
for(int j=i+;j<tot;j++)
while(r.a[j][i])
{
int tmp=r.a[i][i]/r.a[j][i];
for(int l=i;l<tot;l++)
{
int tp=r.a[i][l];r.a[i][l]=r.a[j][l];//i=j;
r.a[j][l]=(tp-r.a[j][l]*tmp)%mod;//j=i%j
}
fx=-fx;
}
(ret*=r.a[i][i])%=mod; //不要在上面赋值:消下面的时候可能换过来!
}
ret=(ret*fx+mod)%mod;
(fnw*=ret)%=mod;
}
void cal(int x) //当前权值的一个个联通块
{
d.init();l.init();
memcpy(tvis,vis,sizeof vis);tot=;//bh!
dfst(x);dfsx(x,);
r=d-l;
gauss();
}
void dfs(int cr)
{
col[cr]=cnt;
for(int i=head[cr];i;i=ed[i].next)
if(used[i]&&!col[ed[i].y])
dfs(ed[i].y);
}
void solve() //一层
{
memset(nd,,sizeof nd);memset(used,,sizeof used);
for(int i=p0;i<=p1;i++)
if(ed[i].x!=ed[i].y) //边的两边连的是已经缩点后的
used[i]=,nd[ed[i].x]=,nd[ed[i].y]=; //能用的边和涉及的点
memset(vis,,sizeof vis);memset(bh,,sizeof bh);fnw=;
for(int i=;i<=cnt;i++)if(!vis[i]&&nd[i])cal(i); //每个联通块
(ans*=fnw)%=mod;
cnt=;memset(col,,sizeof col); //cnt:现在有多少点(缩点后)
for(int i=;i<=cnt;i++)if(!col[i])cnt++,dfs(i); //缩点
for(int i=p1+;i<=xnt;i++)ed[i].x=col[ed[i].x],ed[i].y=col[ed[i].y];
}
int main()
{
scanf("%d%d",&n,&m);int x,y,w;
for(int i=;i<=n;i++)fa[i]=i;
for(int i=;i<=m;i++)scanf("%d%d%d",&x,&y,&w),add(x,y,w);
for(int i=;i<=n;i++)if(find(i-)!=find(i)){printf("");return ;}//
sort(ed+,ed+xnt+);cnt=n;
for(int i=;i<=xnt;i++)
{
ed[i].next=head[ed[i].x];
head[ed[i].x]=i;
}
for(int i=;i<=xnt;i++)
{
p0=i;while(ed[i+].w==ed[i].w)i++;p1=i;
solve();
}
printf("%d",ans);
return ;
}

只能过样例的

bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)的更多相关文章

  1. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

  2. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  3. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  4. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  5. bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

    有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...

  6. BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理

    考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...

  7. 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

    1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...

  8. 1016: [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][St ...

  9. 1016: [JSOI2008]最小生成树计数 - BZOJ

    Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...

随机推荐

  1. Android开发之旅-获取地理位置的经度和纬度

    在Android应用程序中,可以使用LocationManager来获取移动设备所在的地理位置信息.看如下实例:新建android应用程序TestLocation. 1.activity_main.x ...

  2. 建议50:Python中的高级数据结构

    # -*- coding:utf-8 -*- ''' Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint collections模块包含了内建类型之外 ...

  3. 20145230《JAVA程序设计》第2周学习总结

    20145230 <Java程序设计>第2周学习总结 教材学习内容总结 本周我学习了<JAVA学习笔记>中的第三章内容,让我对JAVA有了进一步的了解.第三章主要是介绍JAVA ...

  4. PHP实现链式操作

    什么是链式操作 我们经常会在一些应用框架中看到如下代码: $db = new Database; $db->where('cid = 9')->order('aid desc')-> ...

  5. Windows10在待机状态时会卡屏的解决方案

    问题:Windows10在待机时,会出现卡屏(鼠标.键盘都无法操作,只能重启电脑),区别于平时我们看得比较多的花屏.蓝屏.黑屏. 原因:经过一段时间的待机,Windows10会进入到降电节能模式,由于 ...

  6. (十三)linux文件系统详解(基于ext2文件系统)【转】

    本文转载自:https://blog.csdn.net/FadeFarAway/article/details/53959639 我们知道,一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如 ...

  7. Golang 连接Kafka

    Kafka介绍 Kafka是Apache软件基金会开发的一个开源流处理平台,由Java和Scala编写:Kafka是一种高吞吐.分布式.基于订阅发布的消息系统. Kafka名称解释 Producer: ...

  8. docker link

    什么是docker的link机制 同一个宿主机上的多个docker容器之间如果想进行通信,可以通过使用容器的ip地址来通信,也可以通过宿主机的ip加上容器暴露出的端口号来通信,前者会导致ip地址的硬编 ...

  9. MVC6 (ASP.NET5) 自定义TagHelper

    1) 在 _ViewImports.cshtml 中引入TagHelper类所在的 Assembly . (注意不是namespace)  : @addTagHelper "*, WebAp ...

  10. springmvc请求参数的绑定和获取

    请求参数的绑定和获取: 获取页面请求的参数,是javaweb必不可少的一个环节,在struts中,是通过再Action中定义属性,或者Model的方式进行数据绑定和获取.需要提供setter或gett ...