zoukankan      html  css  js  c++  java
  • 【BZOJ】【1016】【JSOI2008】最小生成树计数

    Kruskal/并查集+枚举


      唉我还是too naive,orz Hzwer

      一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!!

      所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数。然后,对于每种边权,比方说出现了$v_i$次,那么可以替换的一定是形成环的!且这种边权的选取方案对其他边权的没有影响,我就可以$2^{v_i}$枚举每条边是否选取,暴力找出这$v_i$条边的可行方案数,这个复杂度并不高,因为题目保证了这里的$v_i leq 10$。

    proverbs:

    最小生成树的两个性质:

    1、边权相等的边的个数一定。

    2、做完边权为w的所有边时,图的连通性相同。

     1 /**************************************************************
     2     Problem: 1016
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:8 ms
     7     Memory:1300 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1016
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=110,INF=~0u>>2,MOD=31011;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 int n,m,fa[N];
    32 struct edge{int u,v,w;}e[1010];
    33 struct data{int l,r,v;}a[1010];
    34 bool cmp(edge a,edge b){return a.w<b.w;}
    35 int Find(int x){return fa[x]==x?x:Find(fa[x]);}
    36 int sum,ans=1,tot;
    37 void dfs(int x,int now,int k){
    38     if (now==a[x].r+1){
    39         if (k==a[x].v) sum++;
    40         return;
    41     }
    42     int p=Find(e[now].u),q=Find(e[now].v);
    43     if (p!=q){
    44         fa[p]=q;
    45         dfs(x,now+1,k+1);
    46         fa[p]=p; fa[q]=q;
    47     }
    48     dfs(x,now+1,k);
    49 }
    50 int main(){
    51 #ifndef ONLINE_JUDGE
    52     freopen("1016.in","r",stdin);
    53     freopen("1016.out","w",stdout);
    54 #endif
    55     n=getint(); m=getint();
    56     F(i,1,m){
    57         e[i].u=getint(); e[i].v=getint(); e[i].w=getint();
    58     }
    59     sort(e+1,e+m+1,cmp);
    60     int cnt=0,now=0;
    61     F(i,1,n) fa[i]=i;
    62     F(i,1,m){
    63         if (i==1||e[i].w!=e[i-1].w) {a[++cnt].l=i;a[cnt-1].r=i-1;}
    64         int p=Find(e[i].u),q=Find(e[i].v);
    65         if (p!=q){ fa[p]=q; a[cnt].v++; tot++;}
    66     }
    67     a[cnt].r=m;
    68     if (tot!=n-1){puts("0");return 0;}
    69     F(i,1,n) fa[i]=i;
    70     F(i,1,cnt){
    71         sum=0;
    72         dfs(i,a[i].l,0);
    73         ans=ans*sum%MOD;
    74         F(j,a[i].l,a[i].r){
    75             int p=Find(e[j].u),q=Find(e[j].v);
    76             if (p!=q) fa[p]=q;
    77         }
    78     }
    79     printf("%d
    ",ans);
    80     return 0;
    81 }
    View Code

    1016: [JSOI2008]最小生成树计数

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3312  Solved: 1311
    [Submit][Status][Discuss]

    Description

    现 在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不 同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

    Input

    第 一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10 条。

    Output

    输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

    Sample Input

    4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 1
    3 4 1

    Sample Output

    8

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    记录Linq中lambda动态表达式的使用方式
    openai-baseline安装过程中遇到的问题及解决方式
    已经安装cuda但是tensorflow仍然使用cpu加速的问题
    OpenAI gym环境--1基本知识
    logging
    tensorflow笔记1.1---------tf.app.run
    OBS源码解析(2)run_program函数
    OBS源码解析(1)main函数
    google开源服务器apprtc的搭建
    网络媒体流的音视频同步
  • 原文地址:https://www.cnblogs.com/Tunix/p/4415971.html
Copyright © 2011-2022 走看看