bzoj1016 [JSOI2008]最小生成树计数
先做一遍kruskal,然后发现不同的方案只可能是相同权值的不同的边干了相同的事
题目又保证了相同权值的边数很少,直接状压即可
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #define N 1005 7 using namespace std; 8 int getnum(int x){ 9 int cnt=0; 10 while(x){cnt+=x&1;x>>=1;} 11 return cnt; 12 } 13 int n,m,ans=1; 14 int fa[N],tmp[N]; 15 int find(int x,int *y){ 16 if(x==y[x])return x; 17 return y[x]=find(y[x],y); 18 } 19 struct edge{int u,v,w;}ed[10*N]; 20 bool cmp(edge a,edge b){return a.w<b.w;} 21 bool vis[10*N]; 22 int bit[15]; 23 int main(){ 24 bit[0]=1; 25 for(int i=1;i<=10;i++)bit[i]=bit[i-1]<<1; 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=n;i++)fa[i]=i; 28 for(int i=1;i<=m;i++) 29 scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w); 30 sort(ed+1,ed+m+1,cmp); 31 for(int i=1,fv,fu;i<=m;i++){ 32 fu=find(ed[i].u,fa);fv=find(ed[i].v,fa); 33 if(fu!=fv){ 34 fa[fu]=fv; 35 vis[i]=1; 36 } 37 } 38 for(int be=1,en,num,len,cnt,flag;be<=m;be++){ 39 for(en=be;en<=m&&ed[en+1].w==ed[be].w;en++); 40 for(int i=1;i<=n;i++)fa[i]=tmp[i]=i; 41 num=n-1;cnt=0; 42 for(int i=1;i<=m;i++){ 43 if(i>=be&&i<=en)continue; 44 if(vis[i]){ 45 int fu=find(ed[i].u,tmp),fv=find(ed[i].v,tmp); 46 tmp[fu]=fv;num--; 47 } 48 } 49 len=en-be+1; 50 for(int i=0;i<bit[len];i++)if(getnum(i)==num){ 51 flag=0; 52 memcpy(fa,tmp,sizeof fa); 53 for(int j=be;j<=en;j++){ 54 if(i&bit[j-be]){ 55 int fu=find(ed[j].u,fa),fv=find(ed[j].v,fa); 56 if(fu==fv){flag=1;break;} 57 fa[fu]=fv; 58 } 59 } 60 if(flag==0)cnt++; 61 } 62 ans=ans*cnt%31011; 63 be=en; 64 } 65 printf("%d\n",ans); 66 return 0; 67 }
人生如梦亦如幻 朝如晨露暮如霞。