【题目链接】
BZOJ 3714: [PA2014]Kuglarz
【解析】
乍一看,没啥思路。。。
经过苦(kan)思(le)冥(ti)想(jie)之后,发现是最小生成树。。。
用 d[i, j] 表示区间 [i, j] 的奇偶性,可以发现,当知道 d[1, i] 和 d[1, i - 1] 时,便可推导出第 i 个杯子下是否藏着球。
因为保证猜出哪个杯子下藏着球的条件就是 d[1, 0],d[1, 1] … d[1, n] 均为已知量,即 n + 1 个点均被包含;所以问题可以转化为图上的生成树问题。
而题目给出的是区间 [i, j] 的奇偶性,对此,我们将其转换为 d[1, i - 1] 和
d[1, j],连一条 (i - 1, j) 的边,以查询费用为边权,求出最小生成树,便是最终的答案。
因为是稠密图,所以 Prim 比 Kruskal 要更快些。
【代码】
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
#define N 2010
using namespace std;
int n;
int G[N][N], dis[N], vis[N];
int main() {
cin >> n;
memset(G, 0x3f, sizeof G);
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) {
int w; scanf("%d", &w);
G[i - 1][j] = G[j][i - 1] = w;
}
LL ans = 0;
memset(dis, 0x3f, sizeof dis);
dis[0] = 0;
for (int k = 0; k <= n; k++) {
int u = 2001;
for (int i = 0; i <= n; i++)
if (!vis[i] && dis[u] > dis[i]) u = i;
vis[u] = 1;
ans += dis[u];
for (int i = 0; i <= n; i++)
if (!vis[i]) dis[i] = min(dis[i], G[u][i]);
}
cout << ans;
return 0;
}