bzoj 1016 深搜

  首先我们知道MST的一些性质,对于这道题来说就是,假设我们先求出一颗MST设为G,由已知边权相同的边最多会有10条,那么假设我们在这10条边中选取size条边∈G,那么我们在这边权相同的边集E中任意选取size条有意义的边,这里的有意义的边的定义为每条边都会造成新的连通性的增加,那么边集E中所有的size条有意义的边的方案我们可以通过dfs求出,然后我们将不同边权的边的方案求连乘,就是MST的方案数。

  ps:我们没有必要求一遍MST,我们可以一边做kruskal,一边维护图的连通性,然后每找到一个权值不同的边集E时深搜。

  反思:做dfs的时候使用并查集维护图的连通性,但是加了路径压缩,这样就会在找块的祖先的时候改变不同节点的父亲,这样就没有办法在dfs时恢复原图,所以我们应该只用并查集维护节点的父亲而不是祖先,找了半天才找到这里的错误。

  

/**************************************************************
    Problem: 1016
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:8 ms
    Memory:820 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 110
#define maxm 1010
#define d39 31011
 
using namespace std;
 
int n,m;
int father[maxn],curfather[maxn];
struct rec
{
    int a,b,len;
} c[maxm];
 
bool cmp(rec a,rec b)
{return (a.len<b.len);}
 
int getfather(int x)
{
    if (father[x]==x) return x;
    return father[x]=getfather(father[x]);
}
 
int getcurfather(int x)
{
    if (curfather[x]==x) return x;
    return getcurfather(curfather[x]);
}
 
int dfs(int l,int r,int size)
{
    //printf("%d %d %d\n",l,r,size);
    if (!size) return 1;
    if (l>r) return 0;
    int fa,fb,cur=0;
    cur=dfs(l+1,r,size);
    fa=getcurfather(c[l].a); fb=getcurfather(c[l].b);
    if (fa!=fb)
    {
        curfather[fa]=fb;
        cur+=dfs(l+1,r,size-1);
        curfather[fa]=fa;
    }
    return cur;
}
 
int main()
{
    int ans=1,cnt=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&c[i].a,&c[i].b,&c[i].len);
    sort(c+1,c+m+1,cmp);
    for (int i=1;i<=n;i++) father[i]=curfather[i]=i;
    int cur=0;
    int l,r,size=0;
    for (int i=1;i<=m+1;i++)
    {
        if (cur!=c[i].len)
        {
            r=i-1;
            //if (i!=1) printf(" %d %d %d\n",l,r,size);
            if (i!=1) ans=(ans*=dfs(l,r,size))%d39;
            l=i;
            size=0;
            cur=c[i].len;
            memcpy(curfather,father,sizeof curfather);
        }
        int fa,fb;
        fa=getfather(c[i].a); fb=getfather(c[i].b);
        if (fa!=fb)
        {
            size++;
            cnt++;
            father[fa]=fb;
        }
    }
    if (cnt!=n-1) printf("0\n"); else printf("%d\n",ans);
    return 0;
}

 

posted on 2014-02-16 22:16  BLADEVIL  阅读(304)  评论(0编辑  收藏  举报