bzoj3714 [PA2014]Kuglarz 最小生成树

题面:

魔术师的桌子上有$n$个杯子排成一行,编号为$1,2,…,n$,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。

花费$c_ij$元,魔术师就会告诉你杯子$i,i+1,…,j$底下藏有球的总数的奇偶性。

采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?

 

我们可以把前$i$个杯子的球的奇偶关系看做一个点$S[i]$

那么,原题相当于最小生成树

使用$prim$算法可以做到$O(n^2)$

 

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
    #define re register
    #define de double
    #define le long double
    #define ri register int
    #define ll long long
    #define sh short
    #define pii pair<int, int>
    #define mp make_pair
    #define pb push_back
    #define tpr template <typename ra>
    #define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
    #define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)    
    extern inline char gc() {
        static char RR[23456], *S = RR + 23333, *T = RR + 23333;
        if(S == T) fread(RR, 1, 23333, stdin), S = RR;
        return *S ++;
    }
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;
    }
    int wr[50], rw;
    #define pc(iw) putchar(iw)
    tpr inline void write(ra o, char c = '\n') {
        if(!o) pc('0');
        if(o < 0) o = -o, pc('-');
        while(o) wr[++ rw] = o % 10, o /= 10;
        while(rw) pc(wr[rw --] + '0');
        pc(c);
    }
    tpr inline void cmin(ra &a, ra b) { if(a > b) a = b; }
    tpr inline void cmax(ra &a, ra b) { if(a < b) a = b; } 
    tpr inline bool ckmin(ra &a, ra b) { return (a > b) ? a = b, 1 : 0; }
    tpr inline bool ckmax(ra &a, ra b) { return (a < b) ? a = b, 1 : 0; }
}
using namespace std;
using namespace remoon;

#define sid 2005

int n;
ll ans;
int vis[sid], low[sid], who[sid];
int w[sid][sid];

inline void MST() {
    vis[1] = 1;
    rep(i, 1, n + 1) low[i] = 1e9 + 5;
    rep(i, 2, n + 1) 
    if(!vis[i] && ckmin(low[i], w[1][i])) who[i] = 1;
    rep(t, 1, n) {
        int nv = -1, dis = 1e9;
        rep(i, 1, n + 1)
        if(!vis[i] && ckmin(dis, low[i])) nv = i;
        ans += dis; vis[nv] = 1;
        rep(i, 1, n + 1)
        if(!vis[i] && ckmin(low[i], w[nv][i])) who[i] = nv;
    }
    write(ans);
}

int main() {
    n = read();
    memset(w, 127, sizeof(w));
    rep(i, 1, n) rep(j, i, n) 
    w[j + 1][i] = w[i][j + 1] = read();
    MST();
    return 0;
}

 

posted @ 2018-10-12 16:28  remoon  阅读(174)  评论(0编辑  收藏  举报