牛客OI周赛4-提高组 A K小生成树(kmst)

K小生成树(kmst)

思路:

暴力+并查集

枚举边的子集,用并查集判断两个点联不联通

代码:

#include
using namespace std;
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define mem(a, b) memset(a, b, sizeof(a))
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
//head

const int N = 30;
piii e[N];
int fa[N], tmp[(1<<25) + 10];
int n, m, top = 0;
int Find(int x) {
    if(x == fa[x]) return x;
    else return Find(fa[x]);
}
void dfs(int i, int cnt, int len) {
    if(m-i+1 + cnt < n-1) return ;//这个剪枝很优秀
    if(i == m+1) {
        if(cnt == n-1) tmp[++top] = len;
        return ;
    }
    dfs(i+1, cnt, len);
    int u = Find(e[i].fi.fi), v = Find(e[i].fi.se);
    if(u != v) {
        fa[u] = v;
        dfs(i+1, cnt+1, len+e[i].se);
        fa[u] = u;
    }
}
int main() {
    int l, r, q;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; i++) {
        scanf("%d %d %d", &e[i].fi.fi, &e[i].fi.se, &e[i].se);
    }
    for (int i = 1; i <= n; i++) fa[i] = i;
    dfs(1, 0, 0);
    sort(tmp+1, tmp+1+top);
    scanf("%d", &q);
    while(q--) {
        scanf("%d %d", &l, &r);
        printf("%d\n", upper_bound(tmp+1, tmp+1+top, r) - lower_bound(tmp+1, tmp+1+top, l));
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/widsom/p/9871901.html

你可能感兴趣的:(牛客OI周赛4-提高组 A K小生成树(kmst))