【BZOJ3714】Kuglarz(最小生成树)
【BZOJ3714】Kuglarz(最小生成树)
题面
Description
魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费c_ij元,魔术师就会告诉你杯子i,i+1,…,j底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?
Input
第一行一个整数n(1<=n<=2000)。
第i+1行(1<=i<=n)有n+1-i个整数,表示每一种询问所需的花费。其中c_ij(对区间[i,j]进行询问的费用,1<=i<=j<=n,1<=c_ij<=10^9)为第i+1行第j+1-i个数。
Output
输出一个整数,表示最少花费。
Sample Input
5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
Sample Output
7
题解
假设前缀和是\(s\)
相当于要知道所有的额\(s[i]-s[0]\)的值
因此,相当于要所有的点构成联通块
连接两个点的费用显然是\(C_{ij}\)
因此,最小生成树就是答案
点数较少,使用\(Prim\)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
ll ans,dis[2222];
bool vis[2222];
int n,g[2222][2222];
void Prim()
{
memset(dis,63,sizeof(dis));dis[1]=0;
for(int i=1;i<=n;++i)
{
int u=0;
for(int j=1;j<=n;++j)
if(!vis[j]&&dis[j]<dis[u])u=j;
ans+=dis[u];vis[u]=true;
for(int j=1;j<=n;++j)
if(!vis[j])dis[j]=min(dis[j],(ll)g[u][j]);
}
}
int main()
{
n=read()+1;
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)g[i][j]=g[j][i]=read();
Prim();
printf("%lld\n",ans);
return 0;
}