zoukankan      html  css  js  c++  java
  • [BZOJ1016][JSOI2008]最小生成树计数

    https://blog.sengxian.com/solutions/bzoj-1016

    先总结一下MST的性质吧:

    1.(圈性质)考虑一条非树边和一些树边构成的环,环上所有树边的权值一定不大于这条非树边。

    2.(割性质)考虑图的一个割,这个割中的最小边一定被选入了MST。

    3.考虑同一张图的两个不同MST A和B,将两个MST的边分别从小到大排列,则每对同一位置的边权都是相等的。

    4.从小到大将MST加入到图中,在加完任一权值的所有边后,图的连通性是固定的。

    考虑利用这些定理,根据(3)和(4),我们只要先求出一个MST,就能知道每种权值的边在MST中要出现多少次,以及每种边权的边全部加完后图的连通块个数。有了这些信息,我们只需要对于每种权值搜索选取哪些边,然后用乘法原理即可得到答案。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1010,mod=31011;
     7 int n,m,ans=1,sm,cnt,tot,fa[N],sz[N];
     8 struct E{ int u,v,w; }e[N];
     9 struct P{ int l,r,v; }a[N];
    10 
    11 inline int rd(){
    12     int x=0; char ch=getchar();
    13     while (ch<'0' || ch>'9') ch=getchar();
    14     while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    15     return x;
    16 }
    17 
    18 bool cmp(E a,E b){ return a.w<b.w; }
    19 int find(int x){ return (x==fa[x]) ? x : find(fa[x]); }
    20 
    21 void dfs(int x,int now,int k){
    22     if (now==a[x].r+1){
    23         if (k==a[x].v) sm++;
    24         return;
    25     }
    26     int p=find(e[now].u),q=find(e[now].v);
    27     if (p!=q){
    28         if (sz[p]<sz[q]) swap(p,q);
    29         fa[p]=q; sz[q]+=sz[p];
    30         dfs(x,now+1,k+1);
    31         fa[p]=p; sz[q]-=sz[p];
    32     }
    33     dfs(x,now+1,k);
    34 }
    35 
    36 int main(){
    37     freopen("bzoj1016.in","r",stdin);
    38     freopen("bzoj1016.out","w",stdout);
    39     n=rd(); m=rd();
    40     rep(i,1,n) fa[i]=i,sz[i]=1;
    41     rep(i,1,m) e[i].u=rd(),e[i].v=rd(),e[i].w=rd();
    42     sort(e+1,e+m+1,cmp);
    43     rep(i,1,m){
    44         if (e[i].w!=e[i-1].w) a[cnt].r=i-1,a[++cnt].l=i;
    45         int p=find(e[i].u),q=find(e[i].v);
    46         if (p==q) continue;
    47         a[cnt].v++; tot++;
    48         if (sz[p]>sz[q]) swap(p,q);
    49         fa[p]=q; sz[q]+=sz[p];
    50     }
    51     a[cnt].r=m;
    52     if (tot!=n-1){ puts("0"); return 0; }
    53     rep(i,1,n) fa[i]=i,sz[i]=1;
    54     rep(i,1,cnt){
    55         sm=0; dfs(i,a[i].l,0); ans=ans*sm%mod;
    56         rep(j,a[i].l,a[i].r){
    57             int p=find(e[j].u),q=find(e[j].v);
    58             if (p==q) continue;
    59             if (sz[p]>sz[q]) swap(p,q);
    60             fa[p]=q;
    61         }
    62     }
    63     printf("%d
    ",ans);
    64     return 0;
    65 }
  • 相关阅读:
    Win7 on VirtualBox 看不到 usb device
    framebuffer line_length 參數
    booting logo & booting animation
    charing animation
    vim
    [筆記] Ubuntu Linux 使用 apt-get 指令移除軟體並清理遺留的垃圾
    git 指令
    adb devices 偵測不到 手機
    apt-get 相關設定
    Ubuntu 14 設定 遠端連線,讓別台電腦可以連線進來
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9283294.html
Copyright © 2011-2022 走看看