BZOJ1016 JSOI2008 最小生成树计数
首先必须知道这样一个性质:同一个图的所有最小生成树等权值的边的数量相等、
那么我们先求任意的一个MST、得到每个权值出现的次数(这里可以先离散化方便处理)、
然后根据题目所给的很好的性质(每个权值出现不超过10次)、对每个权值用2^10枚举取边的情况、然后再看是否还存在一棵MST、
复杂度大概是不到2^10*M*M/10的、、
Code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <ctime>
#define ps system("pause")
#define message printf("*\n")
#define pb push_back
#define X first
#define Y second
using namespace std;
struct node{
int a,b,w;
}edge[2010];
int f[110],use[10010],powe[20];
int cnt,n,m,minnum,ans,cur,res;
int find(int x){
if (f[x]==x) return x;
f[x]=find(f[x]);
return f[x];
}
bool cmp(node aa,node bb){
return aa.w<bb.w;
}
void setup(){
int cur=1;
for (int i=1;i<=m;i++)
if (edge[i].w!=edge[i+1].w) edge[i].w=cur++;
else edge[i].w=cur;
}
int calc(int x){
int v=0;
while (x){
v+=x&1;
x/=2;
}
return v;
}
bool check(int x,int sit){
cnt=n;res=edge[x].w*use[edge[x].w];
for (int i=1;i<=n;i++) f[i]=i;
for (int i=x;edge[i].w==edge[x].w;i++){
if (sit&1){
f[edge[i].a]=find(edge[i].a);
f[edge[i].b]=find(edge[i].b);
if (f[edge[i].a]!=f[edge[i].b]){
f[f[edge[i].b]]=f[edge[i].a];
--cnt;
}
}
sit/=2;
}
for (int i=1;i<=m && cnt>1;i++){
if (edge[i].w==edge[x].w) continue;
f[edge[i].a]=find(edge[i].a);
f[edge[i].b]=find(edge[i].b);
if (f[edge[i].a]==f[edge[i].b]) continue;
f[f[edge[i].b]]=f[edge[i].a];
res+=edge[i].w;
if (--cnt==1) break;
}
return (cnt==1 && res==minnum);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].w);
sort(edge+1,edge+m+1,cmp);
setup();
cnt=n;minnum=0;
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=m && cnt>1;i++){
f[edge[i].a]=find(edge[i].a);
f[edge[i].b]=find(edge[i].b);
if (f[edge[i].a]==f[edge[i].b]) continue;
f[f[edge[i].b]]=f[edge[i].a];
use[edge[i].w]++;
minnum+=edge[i].w;
if (--cnt==1) break;
}
if (cnt!=1){
printf("0\n");
return 0;
}
ans=1;powe[0]=1;
for (int i=1;i<=10;i++) powe[i]=powe[i-1]*2;
for (int i=1;i<=m;){
int j=i+1;
while (edge[i].w==edge[j].w) j++;
if (use[edge[i].w]){
cur=0;
for (int sit=0;sit<powe[j-i];sit++)
if (calc(sit)==use[edge[i].w] && check(i,sit)) cur++;
ans=ans*cur%31011;
}
i=j;
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号