bzoj1016: [JSOI2008]最小生成樹計數

題目鏈接

bzoj1016

題目描述

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

題解

在所有的最小生成樹中相同權值的邊選的個數都是一樣的,並且互不干擾。
我們可以對每一種相同權值的邊都搜一下有多少種不同的選擇,乘起來就是答案。這題保證了相同權值的邊不超過10,所有搜索是不會超時的。
如果相同權值的邊再多一些,可以用行列式來做。可以參考http://www.cnblogs.com/Fatedayt/archive/2012/05/10/2494877.html


#include<cstdio>
#include<algorithm>
using namespace std;
struct edge{
    int x,y,data;
    friend bool operator <(edge a,edge b){
        return a.data<b.data;
    }
}e[1010];
struct node{
    int data,num,size;
}c[1010];
int f[110],cnt,tot,n,m,ans,sum;
int get(int x){return f[x]==x?x:get(f[x]);}
bool combine(int x,int y){
    x=get(x); y=get(y);
    if(x==y) return false;
    f[x]=y; return true;
}
void dfs(int x,int y,int k,int now){
    if(x>y){
        if(k==now) sum++;
        return;
    }
    int p=get(e[x].x),q=get(e[x].y);
    if(p!=q){
        f[p]=q;
        dfs(x+1,y,k,now+1);
        f[p]=p;
    }
    dfs(x+1,y,k,now);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) 
    scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].data);
    sort(e+1,e+1+m);
    e[m+1].data=-1;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        if(combine(e[i].x,e[i].y)) cnt++,ans++;
        if(e[i].data!=e[i+1].data){
            c[++tot].data=e[i].data;
            c[tot].num=cnt;
            c[tot].size=i;
            cnt=0;
        }
    }
    ans=ans==n-1;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=tot;i++){
        sum=0;
        dfs(c[i-1].size+1,c[i].size,c[i].num,0);
        ans=(long long)ans*sum%31011;
        for(int j=c[i-1].size+1;j<=c[i].size;j++) 
        combine(e[j].x,e[j].y);
    }
    printf("%d\n",ans);
    return 0;
}
發佈了60 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章