BZOJ 1016 最小生成树计数

需要明确的是 对于图的每一个MST,所有的边权排序后的结果都是一样的。

先求出图中的一个MST,对于图中权值和MST中相同的一些边,可以对MST中的边替换形成新的MST,这种替换的条件是和原来的MST的这条边构成的联通性应该是一样的。

可以用dfs找出对于原MST中每个权值的边有多少种选择。最后用乘法原理算一下即可。

 

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF (LL)1<<60
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=105;
//Code begin...
 
struct Edge{int u, v, w, flag;}edge[1005];
struct Node{int num, w;}minw[N];
int fa[N], n, m, fa1[N], p[15], now=0;
 
int find(int x)
{
    int s, temp;
    for (s=x; fa[s]>=0; s=fa[s]) ;
    while (s!=x) temp=fa[x], fa[x]=s, x=temp;
    return s;
}
void union_set(int x, int y)
{
    int temp = fa[x]+fa[y];
    if (fa[x]>fa[y]) fa[x]=y, fa[y]=temp;
    else fa[y]=x, fa[x] = temp;
}
bool comp(Edge a, Edge b){return a.w<b.w;}
bool Kruskal()
{
    mem(fa,-1);
    sort(edge+1,edge+m+1,comp);
    int cnt=0;
    FOR(i,1,m) {
        int u=edge[i].u, v=edge[i].v, w=edge[i].w, t1=find(u), t2=find(v);
        if (t1!=t2) {
            union_set(t1,t2);
            ++cnt;
            edge[i].flag=1;
            if (minw[now].w!=w) minw[++now].w=w, minw[now].num=1;
            else minw[now].num++;
        }
        if (cnt==n-1) break;
    }
    return cnt==n-1;
}
void copy(){FOR(i,1,n) fa[i]=fa1[i];}
int dfs(int fisrt, int last, int ci, int num)
{
    if (ci==num) {
        copy();
        FOR(i,1,num) {
            int u=find(edge[p[i]].u), v=find(edge[p[i]].v);
            if (u!=v) union_set(u,v);
            else return 0;
        }
        return 1;
    }
    if (fisrt>last) return 0;
    int ans=0;
    FOR(i,fisrt,last) p[ci+1]=i, ans+=dfs(i+1,last,ci+1,num);
    return ans;
}
int main ()
{
    scanf("%d%d",&n,&m);
    FOR(i,1,m) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    if (Kruskal()==0) {puts("0"); return 0;}
    int i=1, ans=1;
    mem(fa,-1);
    FOR(j,1,now) {
        while (edge[i].w!=minw[j].w) ++i;
        int cnt=0;
        FOR(k,1,n) fa1[k]=fa[k];
        while (edge[i].w==minw[j].w) ++i, ++cnt;
        ans=ans*dfs(i-cnt,i-1,0,minw[j].num)%31011;
        copy();
        FOR(k,i-cnt,i-1) if (edge[k].flag) union_set(find(edge[k].u),find(edge[k].v));
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2017-03-01 15:09  free-loop  阅读(...)  评论(... 编辑 收藏