题目: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. $.queue() 与 $.dequeue() -- 队列

    JQuery 运用队列为动画模块服务,但好像它应该有更多用处,我觉得的,那试试就知道咯. 简单的来讲,它就是形成队列和出列, 也就因此可以进行很有规律的回调和延时了呀(暂停感觉有难度),当然这就是后面 ...

  2. ubuntu没有声音解决办法

    cd /usr/lib/dbus-1.0/ chmod +x dbus-daemon-launch-helper sudo gpasswd -a $USER audio sudo killall pu ...

  3. 关于C++ 中的this 的理解

    关键字this 通常被用在一个class内部,指正在被执行的该class的对象(object)在内存中的地址.它是一个指针,其值永远是自身object的地址.

  4. 搭建配置cacti,采集信息监控

    安装cactilamp环境[iyunv@Cacti ~]#service iptables stop //关闭防火墙服务[iyunv@Cacti ~]#chkconfig iptables off / ...

  5. MapReduce-计数器

    计数器 计数器是收集作业统计信息的有效手段之一,用于质量控制或应用级统计.计数器还可辅助诊断系统故障.根据计数器值来记录某一特定事件的发生比分析一堆日志文件容易得多.内置计数器Hadoop为每个作业维 ...

  6. Spark常用算子-KeyValue数据类型的算子

    package com.test; import java.util.ArrayList; import java.util.List; import java.util.Map; import or ...

  7. java异常中的finally(二)

    对于含有return语句的情况,这里我们可以简单地总结如下: try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况: 情况一:如果fi ...

  8. DataGrid合并单元格(wpf)

    在网上搜索wpf合并单元格,一直没搜索到,没办法,只能自己想办法搞定了.其实就是DataGrid套DataGrid,为了方便支持Column拖动,在合并的DataGridColumn那一列的Heade ...

  9. WebAPI序列化后的时间中含有“T”的解决方法

    问题: { "name": "abc", "time": "2015-02-10T15:18:21.7046433+08:00&q ...

  10. python中的数据类型和常用运算符

    一. python中常见的数据类型 1. 整数:任何时候运算都是精确的 2. 浮点数:运算的时候,可能会有四舍五入 3. 字符串:字符串是以单引号'或双引号"括起来的任意文本 1) 同类型的 ...