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

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

跑一遍克鲁斯卡尔,记录每种权值的边有多少条,然后状压枚举满足条件的所有边乘到答案中即可

/**************************************************************
    Problem: 1016
    User: walfy
    Language: C++
    Result: Accepted
    Time:68 ms
    Memory:1452 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double g=10.0,eps=1e-12;
const int N=1000+10,maxn=200000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
struct edge{
    int u,v,c;
    bool operator<(const edge &rhs)const{
        return c<rhs.c;
    }
}e[N];
map<int,int>ans,id;
vector<pii>v[N];
int fa[N],prefa[N];
int Find(int x)
{
    return fa[x]==x?x:fa[x]=Find(fa[x]);
}
int main()
{
    fio;
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)fa[i]=i;
    int cnt=0;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        e[i]={a,b,c};
    }
    sort(e,e+m);
    for(int i=0;i<m;i++)
    {
        if(!id[e[i].c])id[e[i].c]=++cnt;
        v[id[e[i].c]].pb(mp(e[i].u,e[i].v));
        int x=e[i].u,y=e[i].v;
        int fx=Find(x),fy=Find(y);
        if(fx!=fy)fa[fx]=fy,ans[e[i].c]++;
    }
    for(int i=2;i<=n;i++)
        if(Find(i)!=Find(i-1))
        {
            cout<<0<<"\n";
            return 0;
        }
    for(int i=1;i<=n;i++)fa[i]=i;
    map<int,int>::iterator it=id.begin();
    ll res=1;
    for(;it!=id.end();it++)
    {
        for(int i=1;i<=n;i++)prefa[i]=fa[i];
//        for(int i=0;i<v[it->se].size();i++)printf("%d %d %d\n",i,v[it->se][i].fi,v[it->se][i].se);
//        puts("");
        ll len=v[it->se].size(),go=-1,pp=0;
        for(int i=0;i<(1<<len);i++)
        {
            int num=0;
            for(int j=0;j<len;j++)
                if((i>>j)&1)
                    num++;
            if(num!=ans[it->fi])continue;
            else
            {
 
                bool ok=1;
                for(int j=0;j<len;j++)
                {
                    if((i>>j)&1)
                    {
                        int x=v[it->se][j].fi,y=v[it->se][j].se;
                        int fx=Find(x),fy=Find(y);
                        if(fx!=fy)fa[fx]=fy;
                        else ok=0;
                    }
                }
                if(ok)pp++,go=i;//,printf("%d\n",i);
            }
            for(int j=1;j<=n;j++)fa[j]=prefa[j];
        }
//        printf("%d\n",pp);
        res=(res*pp)%31011;
        if(go==-1)continue;
        for(int j=0;j<len;j++)
        {
            if((go>>j)&1)
            {
                int x=v[it->se][j].fi,y=v[it->se][j].se;
                int fx=Find(x),fy=Find(y);
                if(x!=y)fa[fx]=fy;
            }
        }
    }
    cout<<res<<"\n";
    return 0;
}
/***********************
4 6
 
1 2 1
 
1 3 1
 
1 4 1
 
2 3 2
 
2 4 1
 
3 4 3
***********************/
View Code

 

posted @ 2018-04-15 16:42  walfy  阅读(156)  评论(0编辑  收藏  举报