【BZOJ4031】小Z的房间
【BZOJ1017】魔兽地图

【BZOJ1016】最小生成树计数

Zarxdy34 posted @ 2015年10月21日 21:39 in BZOJ with tags kruskal Matrix-Tree定理 , 448 阅读

  标算应该是DFS+kruskal,其中DFS是计算选一些权值相等的边的方案数的。但是感觉写DFS不高贵就敲Matrix-Tree了,尽管代码量上升了很多。

  Build_Graph1将当前连通块缩点,使用一些权值相等的有用的边,将连通块连接起来,对应的值放进行列式里。

  Build_Graph2将Build_Graph1中剩下的彼此之间没有联通的连通块连接起来(原图中并没有这些边),由于这些边在计算时是必选的,所以不影响答案。

  当然直接写DFS就好了没必要像Zarxdy34一样这么SB...

 

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
using namespace std;
const int maxn=110,maxm=1010,mo=31011;

struct Edge {int x,y,c;}E[maxm];
bool cmp(const Edge &a,const Edge &b) {return a.c<b.c;}

struct Matrix
{
	int a[maxn][maxn];
	int n;

	void Init() {memset(a,0,sizeof(a));}
	int* operator[] (int x) {return a[x];}

	int det()
	{
		int ans=1;
		for (int i=1;i<n;i++) for (int j=1;j<n;j++) a[i][j]=(a[i][j]%mo+mo)%mo;
		for (int i=1;i<n;i++)
		{
			for (int j=i+1;j<n;j++) while (a[j][i])
			{
				int x=a[i][i]/a[j][i];
				for (int k=i;k<n;k++) a[i][k]=(a[i][k]-x*a[j][k]%mo+mo)%mo;
				for (int k=i;k<n;k++) swap(a[i][k],a[j][k]);
				ans=-ans;
			}
		}
		if (ans==-1) ans+=mo;
		for (int i=1;i<n;i++) ans=ans*a[i][i]%mo;
		return ans;
	}
}M;

int Find(int *f,int x) {return x==f[x]?x:f[x]=Find(f,f[x]);}

int f[maxn],f2[maxn];
int vis[maxn];
int id[maxn],ids;
int n,m,ans;

void Build_Graph1(int l,int r)
{
	memset(vis,0,sizeof(vis));
	memset(id,0,sizeof(id));
	ids=0;
	for (int i=l;i<=r;i++) if (Find(f,E[i].x)!=Find(f,E[i].y)) f2[Find(f2,E[i].x)]=Find(f2,E[i].y),vis[f[E[i].x]]=1,vis[f[E[i].y]]=1;
	for (int i=1;i<=n;i++) if (vis[i]) id[i]=++ids;
	for (int i=l;i<=r;i++) if (f[E[i].x]!=f[E[i].y])
	{
		int idx=id[f[E[i].x]],idy=id[f[E[i].y]];
		M[idx][idx]++;M[idy][idy]++;
		M[idx][idy]--;M[idy][idx]--;
	}
	M.n=ids;
}

int q[maxn],qn;

void Build_Graph2(int l,int r)
{
	memset(vis,0,sizeof(vis));
	for (int i=l;i<=r;i++) if (f[E[i].x]!=f[E[i].y]) vis[Find(f2,E[i].x)]=1,vis[Find(f2,E[i].y)]=1;
	qn=0;
	for (int i=1;i<=n;i++) if (vis[i]) q[++qn]=i;
	for (int i=1;i<qn;i++)
	{
		int idx=id[q[i]],idy=id[q[i+1]];
		M[idx][idx]++;M[idy][idy]++;
		M[idx][idy]--;M[idy][idx]--;
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].c);
	for (int i=1;i<=n;i++) f[i]=f2[i]=i;
	sort(E+1,E+1+m,cmp);
	ans=1;
	for (int l=1,r=1;l<=m;l=r+1)
	{
		r=l;
		while (r<m && E[r+1].c==E[l].c) r++;
		M.Init();
		Build_Graph1(l,r);
		Build_Graph2(l,r);
		ans=ans*M.det()%mo;
		for (int i=1;i<=n;i++) f[i]=Find(f2,i);
	}
	for (int i=1;i<n;i++) if (Find(f,i)!=Find(f,i+1)) {printf("0\n");return 0;}
	printf("%d\n",ans);
	return 0;
}

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter