[BZOJ1016][JSOI2008]最小生成树计数 最小生成树 搜索
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1016
做这道题之前需要知道一些结论,同一个图的最小生成树中相同权值的边的个数是不会变的,如果有一种方案中权值为666的边有233条,那么另一种方案一定也是这样,并且它们在图中对连通性的影响也是相同的。
于是我们先求出一种方案,记录下每种权值的边对应的数量。然后把权值相同的边分为一组,对于每一组搜索选出边的合法方案,乘法原理一下答案就出来了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int mod=31011; 6 int inline readint(){ 7 int Num;char ch; 8 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 9 while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0'; 10 return Num; 11 } 12 int n,m; 13 struct EDGE{ 14 int u,v,w; 15 }e[2010],a[1010]; 16 int cnt=0,tot=0; 17 bool cmp(EDGE a,EDGE b){ 18 return a.w<b.w; 19 } 20 int fa[110]; 21 int getfa(int x){ 22 return fa[x]==x?x:getfa(fa[x]); 23 } 24 int sum=0; 25 void dfs(int x,int pos,int k){ 26 if(pos==a[x].v+1){ 27 if(k==a[x].w) sum++; 28 return; 29 } 30 int fu=getfa(e[pos].u), 31 fv=getfa(e[pos].v); 32 if(fu!=fv){ 33 fa[fu]=fv; 34 dfs(x,pos+1,k+1); 35 fa[fu]=fu; 36 fa[fv]=fv; 37 } 38 dfs(x,pos+1,k); 39 } 40 int main(){ 41 n=readint(); 42 m=readint(); 43 for(int i=1;i<=m;i++){ 44 e[i].u=readint(); 45 e[i].v=readint(); 46 e[i].w=readint(); 47 } 48 sort(e+1,e+1+m,cmp); 49 for(int i=1;i<=n;i++) fa[i]=i; 50 for(int i=1;i<=m;i++){ 51 if(e[i].w!=e[i-1].w){ 52 a[cnt].v=i-1; 53 a[++cnt].u=i; 54 } 55 int fu=getfa(e[i].u), 56 fv=getfa(e[i].v); 57 if(fu!=fv){ 58 fa[fu]=fv; 59 a[cnt].w++; 60 tot++; 61 } 62 } 63 a[cnt].v=m; 64 if(tot!=n-1){ 65 puts("0"); 66 return 0; 67 } 68 for(int i=1;i<=n;i++) fa[i]=i; 69 int ans=1; 70 for(int i=1;i<=cnt;i++){ 71 sum=0; 72 dfs(i,a[i].u,0); 73 ans=ans*sum%mod; 74 for(int j=a[i].u;j<=a[i].v;j++){ 75 int fu=getfa(e[j].u), 76 fv=getfa(e[j].v); 77 if(fu!=fv) fa[fu]=fv; 78 } 79 } 80 printf("%d\n",ans); 81 return 0; 82 }