【BZOJ3714】Kuglarz(最小生成树)

【BZOJ3714】Kuglarz(最小生成树)

题面

BZOJ

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;
}

posted @ 2018-03-28 14:48  小蒟蒻yyb  阅读(283)  评论(0编辑  收藏  举报