您的位置:首页 > Web前端 > JavaScript

[矩阵树定理 模板题] BZOJ 1016 [JSOI2008]最小生成树计数 & HDU 4408 Minimum Spanning Tree

2017-02-17 21:30 513 查看
根据Kruscal算法的过程 我们可以得到一些结论

来自 这里

如果 A,B 同为 G 的最小生成树,且 A 的边权从小到大为 w(a1),w(a2),w(a3),⋯w(an),B 的边权从小到大为 w(b1),w(b2),w(b3),⋯w(bn),则有 w(ai)=w(bi)。

如果 A,B 同为 G 的最小生成树,如果 A,B 都从零开始从小到大加边(A 加 A 的边,B 加 B 的边)的话,每种权值加完后图的联通性相同。

如果在最小生成树 A 中权值为 v 的边有 k 条,用任意 k 条权值为 v 的边替换 A 中的权为 v 的边且不产生环的方案都是一棵合法最小生成树。

然后就可以干些奇奇怪怪的事情 按边权分阶段 然后这些边会把某些连通块缩成一个大连通块 这些大连通块之间互不影响 只要对这些大连通块分别做矩阵树定理求余子式 用乘法原理就好了

可能还是这里讲的比较清楚啊

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=105;
const int M=1005;
const int P=31011;

struct Tset{
int fat
;
void init(int n){ for (int i=1;i<=n;i++) fat[i]=i; }
int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); }
}S1,S2;

struct edge{
int u,v,w;
bool operator < (const edge &B) const{ return w<B.w; }
}ed[M];

int n,m,ans=1;
int A

;
int sta

,top
;
int a

;

inline int det(int n){
int ret=1;
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=(a[i][j]%P+P)%P;
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]+P-a[j][k]*t%P)%P;
for (int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
ret=P-ret;
}
if (!a[i][i]) return 0;
ret=ret*a[i][i]%P;
}
return ret;
}

int main(){
int last=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m); if (m<n-1) return printf("0\n"),0;
for (int i=1;i<=m;i++) read(ed[i].u),read(ed[i].v),read(ed[i].w);
sort(ed+1,ed+m+1); S1.init(n); S2.init(n);
for (int i=1;i<=m+1;i++){
if ((i>1 && ed[i].w!=ed[i-1].w) || i==m+1){
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]++,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]++;
for (int j=1;j<=n;j++)
if (S2.Fat(j)==j)
sta[S1.Fat(j)][++top[S1.Fat(j)]]=j;
for (int j=1;j<=n;j++)
if (top[j]>1){
for (int k=1;k<=top[j];k++) a[k][k]=0;
for (int k=1;k<=top[j];k++)
for (int l=k+1;l<=top[j];l++){
int x=sta[j][k],y=sta[j][l];
a[k][l]=-A[x][y]; a[l][k]=-A[x][y];
a[k][k]+=A[x][y]; a[l][l]+=A[x][y];
}
(ans*=det(top[j]-1))%=P;
}
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]--,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]--;
for (int j=1;j<=n;j++)
S2.fat[j]=S1.Fat(j),top[j]=0;
last=i;
}
int x=S1.Fat(ed[i].u),y=S1.Fat(ed[i].v);
if (x==y) continue;
S1.fat[x]=y;
}
int cnt=0;
for (int i=1;i<=n;i++)
cnt+=S1.Fat(i)==i;
printf("%d\n",cnt==1?ans:0);
return 0;
}


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=105;
const int M=1005;

struct Tset{
int fat
;
void init(int n){ for (int i=1;i<=n;i++) fat[i]=i; }
int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); }
}S1,S2;

struct edge{
int u,v,w;
bool operator < (const edge &B) const{ return w<B.w; }
}ed[M];

int n,m,ans,P;
int A

;
int sta

,top
;
int a

;

inline int det(int n){
int ret=1;
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=(a[i][j]%P+P)%P;
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]+P-(ll)a[j][k]*t%P)%P;
for (int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
ret=P-ret;
}
if (!a[i][i]) return 0;
ret=(ll)ret*a[i][i]%P;
}
return ret;
}

int main(){
int last;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
while (1){
read(n); read(m); read(P); if (!n && !m && !P) break;
ans=1; last=0;
for (int i=1;i<=m;i++) read(ed[i].u),read(ed[i].v),read(ed[i].w);
if (m<n-1) { printf("0\n"); continue; }
sort(ed+1,ed+m+1); S1.init(n); S2.init(n);
for (int i=1;i<=m+1;i++){
if ((i>1 && ed[i].w!=ed[i-1].w) || i==m+1){
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]++,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]++;
for (int j=1;j<=n;j++)
if (S2.Fat(j)==j)
sta[S1.Fat(j)][++top[S1.Fat(j)]]=j;
for (int j=1;j<=n;j++)
if (top[j]>1){
for (int k=1;k<=top[j];k++) a[k][k]=0;
for (int k=1;k<=top[j];k++)
for (int l=k+1;l<=top[j];l++){
int x=sta[j][k],y=sta[j][l];
a[k][l]=-A[x][y]; a[l][k]=-A[x][y];
a[k][k]+=A[x][y]; a[l][l]+=A[x][y];
}
ans=(ll)ans*det(top[j]-1)%P;
}
for (int j=last;j<i;j++)
A[S2.Fat(ed[j].u)][S2.Fat(ed[j].v)]--,A[S2.Fat(ed[j].v)][S2.Fat(ed[j].u)]--;
for (int j=1;j<=n;j++)
S2.fat[j]=S1.Fat(j),top[j]=0;
last=i;
}
int x=S1.Fat(ed[i].u),y=S1.Fat(ed[i].v);
if (x==y) continue;
S1.fat[x]=y;
}
int cnt=0;
for (int i=1;i<=n;i++) cnt+=S1.Fat(i)==i;
printf("%d\n",cnt==1?ans%P:0);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: