【JSOI 2008】【BZOJ 1016】最小生成数计数

来源:互联网 发布:软件测试人员招聘 编辑:程序博客网 时间:2024/05/22 03:16

这题题目中有一个很显眼的提示,每种权值的边不会超过10条,这提示我们可以采用些暴力方法。
首先在每个最小生成树中有两个结论:
1、每种权值的边数相等。
2、每种权值所选边构建后图的联通形态相同。
1比较好理解,若1不成立,则最小生成树总权值不固定。
2可以通过Kruskal算法流程来理解。
code:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct hq{    int sum;    int num[1001];}stack[1001],tot[1001];struct hp{    int u,v,w;}a[1001];int father[1001],now[1001],fathernow[1001],fatherlast[1001];int b[1001],n,m,size,sum=0,t=0,ans=1;int cmp(const hp &a,const hp &b){    if (a.w<b.w) return 1;    else return 0;}int findnow(int x){    if (x!=fathernow[x])      fathernow[x]=findnow(fathernow[x]);    return fathernow[x];}int find(int x){    if (x!=father[x])      father[x]=find(father[x]);    return father[x];}bool judge(){    int i,r1,r2;    bool f=false;    for (i=1;i<=n;++i)      fathernow[i]=fatherlast[i];    for (i=1;i<=t;++i)      {        r1=findnow(a[now[i]].u);        r2=findnow(a[now[i]].v);        if (r1<r2)          fathernow[r1]=fathernow[r2];        else          {            if (r2<r1)              fathernow[r2]=fathernow[r1];            else              f=true;          }      }    for (i=1;i<=n;++i)      findnow(i),find(i);    for (i=1;i<=n;++i)      if (fathernow[i]!=father[i])        f=true;    for (i=1;i<=n;++i)      fathernow[i]=fatherlast[i];    if (f)      return false;    else      return true;}void work(int wgt,int i,int last){    int j;    if (i==tot[wgt].sum+1)      {        if (judge())          sum=(sum+1)%31011;        return;      }    for (j=last+1;j<=stack[wgt].sum;++j)      {        now[++t]=stack[wgt].num[j];        work(wgt,i+1,j);        --t;      }}int main(){    int i,r1,r2,j,k=0,wgt=0;    scanf("%d%d",&n,&m);    for (i=1;i<=m;++i)      {        scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);        b[i]=a[i].w;      }    sort(b+1,b+m+1);    size=unique(b+1,+b+m+1)-b-1;    for (i=1;i<=m;++i)      a[i].w=upper_bound(b+1,b+size+1,a[i].w)-b-1;    sort(a+1,a+m+1,cmp);    for (i=1;i<=m;++i)      stack[a[i].w].num[++stack[a[i].w].sum]=i;    for (i=1;i<=n;++i)      father[i]=i;    for (i=1;i<=m;++i)      {        r1=find(a[i].u); r2=find(a[i].v);         if (r1!=r2)          {            tot[a[i].w].num[++tot[a[i].w].sum]=i;            wgt+=a[i].w;            father[r1]=r2;            k++;            size=a[i].w;          }             if (k==n-1)          break;        }    if (k!=n-1)      printf("0\n");    else      {        for (i=1;i<=n;++i)          father[i]=fatherlast[i]=i;        for (i=1;i<=size;++i)          {            for (j=1;j<=tot[i].sum;++j)              {                r1=find(a[tot[i].num[j]].u);                r2=find(a[tot[i].num[j]].v);                if (r1<r2)                  father[r1]=father[r2];                if (r2<r1)                  father[r2]=father[r1];              }            memset(now,0,sizeof(now));            t=0; sum=0;            work(i,1,0);              ans=(ans*sum)%31011;            for (j=1;j<=n;++j)              fatherlast[j]=father[j];          }        printf("%d\n",ans);      }}
1 1