Description
魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费c_ij元,魔术师就会告诉你杯子i,i+1,…,j底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?
1<=n<=2000
1<=c_ij<=10^9
Solution
真是奇妙啊
实际上需要确认所有点的前缀奇偶性,那么对于一条边(x,y)就连(x-1,y),这样跑出来最小生成树就是答案了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=1605;
const int E=N/2*N;
struct edge {int x,y,w;} e[E];
int fa[N],edCnt;
int get_father(int now) {
if (!fa[now]) return now;
return fa[now]=get_father(fa[now]);
}
bool cmp(edge a,edge b) {
return a.w<b.w;
}
bool merge(int x,int y) {
x=get_father(x); y=get_father(y);
if (x==y) return false;
fa[x]=y;
return true;
}
int main(void) {
int n; scanf("%d",&n);
rep(i,1,n) {
rep(j,i,n) {
int w; scanf("%d",&w);
e[++edCnt]=(edge) {i,j+1,w};
}
}
std:: sort(e+1,e+edCnt+1,cmp);
LL ans=0; int tot=0;
rep(i,1,edCnt) {
if (merge(e[i].x,e[i].y)) {
ans+=e[i].w;
tot++;
}
if (tot==n) break;
}
printf("%lld\n", ans);
return 0;
}