码迷,mamicode.com
首页 > Web开发 > 详细

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

时间:2015-06-06 09:16:25      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:

这题题目中有一个很显眼的提示,每种权值的边不会超过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);
      }
}

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

标签:

原文地址:http://blog.csdn.net/lcomyn/article/details/46381987

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!