题目: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. 【HackerRank】 Sherlock and The Beast

    Sherlock and The Beast Sherlock Holmes is getting paranoid about Professor Moriarty, his archenemy. ...

  2. HDU 2603 二分匹配

    #include <queue>#include <vector>#include <cstdio>#include <cstring>#include ...

  3. 算法总结之 构造数组MaxTree

    一个数组的MaxTree定义如下: 数组必须没有重复元素 MaxTree是一颗二叉树,数组的每一个值对应一个二叉树的节点 包括MaxTre树在内且在其中的每一颗子树上,值最大的节点都是树的头 给定一个 ...

  4. shell 读取文件的每一行内容并输出

    (1)#!/bin/bash while read linedo    echo $linedone < file (2)#!/bin/bash cat file  | while read l ...

  5. js多个<ul>相应不同的点击事件

    $('ul').on("click","li#left",function(){ currentProvince = $(this).text().replac ...

  6. Kafka详解一:Kafka简介

    问题导读 1.Kafka有何特性?2.Kafka有哪些组件? 背景:     当今社会各种应用系统诸如商业.社交.搜索.浏览等像信息工厂一样不断的生产出各种信息,在大数据时代,我们面临如下几个挑战: ...

  7. Ubuntu 16.04 安装 RabbitMQ

    Ubuntu 16.04 安装 RabbitMQ(注意,服务器安全组需要添加15672 和5672端口) #1 更新 $ sudo apt-get update$ sudo apt-get upgra ...

  8. 透透彻彻IoC

    本文转载自:http://stamen.iteye.com/blog/1489223/ 引述:IoC(控制反转:Inverse of Control)是Spring容器的内核,AOP.声明式事务等功能 ...

  9. OpenStack网络新项目Dragonflow研究

    https://www.ustack.com/blog/openstack-dragonflow/ 本文由2015年5月30日举行的OpenStack Meetup北京上的演讲整理而成,演讲者为Uni ...

  10. Haproxy与OpenStack-API安全

    转 http://wsfdl.com/devops/2014/12/24/Haproxy%E4%B8%8EOpenStack-API%E5%AE%89%E5%85%A8.html Haproxy 作为 ...