# bzoj 1016 JSOI2008 最小生成树计数

我都不忍心吐槽了。

这么水的暴力我一开始竟然想写链剖！！！

对于某个权值，相同的边不会超过10条。于是，暴力，然后乘起来。

注意特判！特判！图不连通的时候输出0。

我的程序在不联通的时候会输出奇怪的数字……要崩溃了……

上代码：

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#define N 111
#define M 1011
#define yu 31011
#define inf 0x7f7f7f7f
using namespace std;

struct sss
{
int x, y;
int val;
}bian[M];
int n, m;
int fa[N];
int use[M] = {0}, same[15], samenum = 0;
long long ans = 1, minval;

bool cmp(sss x, sss y) { return x.val < y.val; }

int find(int x)
{
if (fa[x] == x) return x;
fa[x] = find(fa[x]);
return fa[x];
}

long long kru()
{
long long nowval = 0; int nowc = n;
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i)
{
int x = find(bian[i].x);
int y = find(bian[i].y);
if (use[i] == 1 && x == y) return 0; // use[i] == 1 用 2 不用
if (use[i] == 2) continue;
if (x != y)
{
fa[x] = y;
nowval += bian[i].val;
nowc --;
}
}
if (nowc != 1) return 0;
else return nowval;
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i)
scanf("%d%d%d", &bian[i].x, &bian[i].y, &bian[i].val);
sort(bian+1, bian+1+m, cmp);
bian[0].val = -inf; bian[m+1].val = -inf;
minval = kru();
if (minval == 0)
{
printf("0\n");
return 0;
}
for (int w = 1; w <= m; ++w)
{
if (bian[w].val != bian[w+1].val) continue;
while (bian[w].val == bian[w-1].val) {same[++samenum] = w++;}
w--;
int zans = 0;
int cou = (1 << samenum)-1;
for (int i = 0; i <= cou; ++i)
{
int j = i, thisb = 1;
for (int k = 1; k  <= samenum; ++k) use[same[k]] = 2;
while (j){if (j & 1) use[same[thisb]] = 1;j >>= 1; thisb++;}
if (kru() == minval) zans++;
}
for (int i = 1; i <= samenum; ++i) use[same[i]] = 0;
ans *= (zans%yu);
ans %= yu;
}
printf("%lld\n", ans%yu);
return 0;
}

posted @ 2014-10-19 10:44  handsomeJian  阅读(118)  评论(0编辑  收藏