zoukankan      html  css  js  c++  java
  • 【Kruskal+dfs】BZOJ1016- [JSOI2008]最小生成树计数

    【题目大意】

    现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。

    【思路】

    拖欠了三个月整(?)的题目,搞出来弄掉了……本年度写的时候姿势最丑的程序,完全不知道自己在搞些什么,晕乎乎的,算了。

    首先,MST具有以下性质:

    1.对于同一张无向加权图G,它的最小生成树中长度为L的边长度一定。

    2.MST用Kruskal做,处理完长度<=x,此时图的连通性是确定的。

    我其实没有读懂第二句话是什么意思,总之大概理解一下,然后乱搞!怎么搞呢。

    先按照普通的Kruskal,按照边长排序,然后排序,然后记录下排序为i的长度有几条边numss,下标为nstart到nend。然后弄出一组MST的解。这个不需要单独搞,只需要在记录边的条数的时候一边操作一边进行Kruskal(详细见程序)。

    注意一下做完之后有可能进行合并操作的次数,也就是选的边是小于N-1的,也就是没有生成树,特判一下。

    接着dfs,枚举每条边取numss个。由于题目条件相同长度的边至多10个,只需暴搜索2^10。每次就判断一下当前这条边左右两边是否已经在同一个并查集里面了,如果不在就可以尝试取这条边合并两段,dfs;或者这条边不取,直接dfs下去。

    嗯,然后乘法原理就好了!

    什么乱七八糟的题解……

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 #define mod 31011
      7 using namespace std;
      8 const int MAXN=1000+50;
      9 struct node
     10 {
     11     int fr,to,len;
     12     bool operator < (const node &x) const
     13     {
     14         return len<x.len;
     15     }
     16 }edge[MAXN];
     17 int num[MAXN],numss=-1,nstart[MAXN],nend[MAXN];//num[i]长度排序为i的边长需要取多少个,nstart/nend表示长度排序为i的边长排序为几到几 
     18 int n,m,pa[MAXN],tot=0,ans,tmpans; 
     19 int find(int x){return (pa[x]==x?x:find(pa[x]));}
     20 
     21 void dfs(int now,int r,int total,int num)
     22 {
     23     if (num>total) return;
     24     if (now>r)
     25     {
     26         if (num==total) tmpans++;
     27         return;    
     28     }
     29     int u=edge[now].fr,v=edge[now].to;
     30     int fa=find(u),fb=find(v);
     31     if (fa!=fb)
     32     {
     33         pa[fa]=fb;
     34         dfs(now+1,r,total,num+1);
     35         pa[fa]=fa;
     36     } 
     37     dfs(now+1,r,total,num);
     38 }
     39 
     40 void init()
     41 {
     42     scanf("%d%d",&n,&m);
     43     for (int i=0;i<m;i++)
     44     {
     45         int a,b,c;
     46         scanf("%d%d%d",&a,&b,&c);
     47         edge[i]=(node){a,b,c};
     48     }
     49     sort(edge,edge+m);
     50 }
     51 
     52 void kruskal()
     53 {
     54     memset(num,0,sizeof(num));
     55     for (int i=1;i<=n;i++) pa[i]=i;
     56     for (int i=0;i<m;i++)
     57     {
     58         if (i==0 || edge[i].len!=edge[i-1].len)
     59         {
     60             if (i!=1) nend[numss]=i-1;
     61             nstart[++numss]=i;
     62         }
     63         int fa=find(edge[i].fr),fb=find(edge[i].to);
     64         if (fa!=fb)
     65         {
     66             pa[fa]=fb;
     67             num[numss]++;
     68             tot++;
     69         } 
     70     }
     71     nend[numss]=m-1;
     72 }
     73 
     74 void solve()
     75 {
     76     if (tot<n-1) puts("0");
     77     else
     78     {
     79         ans=1;
     80         for (int i=1;i<=n;i++) pa[i]=i;
     81         for (int i=0;i<=numss;i++) 
     82         {
     83             tmpans=0;
     84             dfs(nstart[i],nend[i],num[i],0);
     85             ans=(ans*tmpans)%mod;
     86             for (int j=nstart[i];j<=nend[i];j++)
     87             {
     88                 int u=edge[j].fr,v=edge[j].to;
     89                 int fa=find(u),fb=find(v);
     90                 if (fa!=fb) pa[fa]=fb;
     91             } 
     92         }
     93         printf("%d",ans);
     94     }
     95 }
     96 
     97 int main()
     98 {
     99     freopen("bzoj_1016.in","r",stdin);
    100     freopen("bzoj_1016.out","w",stdout);
    101     init();
    102     kruskal();
    103     solve();
    104     return 0;    
    105 } 
  • 相关阅读:
    Oracle数据库内置函数
    软件测试工程师笔试题带答案
    JavaBean对象与Map对象互相转化
    Android之MVP模式实现登录和网络数据加载
    AndroidStudio使用偷懒插件Butterknife和GsonFormat
    最强 Android Studio 使用小技巧和快捷键
    android--------Retrofit+RxJava的使用
    Android之封装好的异步网络请求框架
    Android之MVC模式的使用
    Andriod的Http请求获取Cookie信息并同步保存,使第二次不用登录也可查看个人信息
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5699517.html
Copyright © 2011-2022 走看看