【题目链接】
【算法】
sum[i]表示前i个杯子中,杯子底下藏有球的杯子总数
那么,知道[i,j]这段区间中,藏有球的杯子总数的奇偶性,相当于知道sum[j] - sum[i-1]的奇偶性
我们发现,知道哪些杯子底下藏有球,就是需要我们知道所有sum[i]的奇偶性
因此,我们只需将所有的(i-1,j)连边,边权为输入数据中给出的费用c(i,j),然后,求出这个图的最小
生成树,即可
【代码】
笔者这题求最小生成树使用的是kruskal算法,不过,事实上prim算法可以达到更优的复杂度,kruskal的
时间复杂度是O(n^2log(n)),而prim的时间复杂度是O(n^2)
#include<bits/stdc++.h> using namespace std; #define MAXN 2010 struct info { int u,v; long long w; } e[MAXN*MAXN]; int n,i,j,tot; long long ans,c; bool cmp(info a,info b) { return a.w < b.w; } class DisjointSet { private : int fa[MAXN]; public : inline void init(int n) { int i; for (i = 1; i <= n; i++) fa[i] = i; } inline int get_root(int x) { if (fa[x] == x) return x; return fa[x] = get_root(fa[x]); } inline void merge(int u,int v) { fa[get_root(u)] = get_root(v); } } s; inline void kruskal() { int i,sx,sy; for (i = 1; i <= tot; i++) { sx = s.get_root(e[i].u); sy = s.get_root(e[i].v); if (sx != sy) { ans += e[i].w; s.merge(e[i].u,e[i].v); } } } int main() { scanf("%d",&n); for (i = 1; i <= n; i++) { for (j = i; j <= n; j++) { scanf("%lld",&c); e[++tot] = (info){i-1,j,c}; } } s.init(n); sort(e+1,e+tot+1,cmp); kruskal(); printf("%lld ",ans); return 0; }