题目: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. Qt+数据库

    前言支持内置数据库: 一.sqlite 1.在头文件中声明数据库对象 QSqlDatabase db; 2.在构造函数中定义对象(最好这样定义,因为对于db来说只需要addDatabase一次,否则多 ...

  2. create_workqueue和create_singlethread_workqueue【转】

    本文转载自:http://bgutech.blog.163.com/blog/static/18261124320116181119889/ 1. 什么是workqueueLinux中的Workque ...

  3. JSP DAO(Model)

    示例代码: 1. Users类 package com.po; public class Users { private String username; private String passwor ...

  4. docker calico安装

      第一步,安装etcd: 请参考以前的文章:  http://www.cnblogs.com/vincenshen/articles/8637949.html 第二步,下载calico: sudo ...

  5. 微信内置浏览器和小程序的 User Agent 区别及判断方法

    通过UA来判断不同的设备或者浏览器是开发者最常用的方式方法,而对于微信开发和小程序也是同样的一个情况,我们可以通过微信内置浏览器 User Agent 信息来判断其具体类型或者设备. 所以子凡就通过徒 ...

  6. Hadoop的Docker镜像构建

    1.Dockerfile ###Dockerfile -- beagin FROM ubuntu:trusty #MAINTAINER The Hue Team "https://githu ...

  7. php攻击漏洞总结

    1.两字节编码(gbk)都存在宽字节攻击问题[character_set_client=gbk] 案例:http://www.cnblogs.com/lcamry/articles/5625276.h ...

  8. compile to 32-bit elf file

    nasm -f elf -o a.o a.asm gcc -c -m32 -o b.o b.c ld -s -m elf_i386 -Ttext 0x30400 -o b.bin b.o a.o

  9. XSS 跨站攻击

    未整理完 介绍 XSS (Cross site Scripting),跨站脚本攻击,为了区分层叠样式表css,所以叫了XSS. 对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的"缓冲区溢 ...

  10. C# 6.0 (VS2015 CTP6)

    /* C# 6.0 demo https://github.com/dotnet/roslyn/wiki/Languages-features-in-C%23-6-and-VB-14 */ using ...