2020.02.04日常总结

P 5994     [ P A 2014 ] K u g l a r z \color{green}{洛谷P5994\ \ \ [PA2014]Kuglarz}

\color{blue}{【题意】:}
在这里插入图片描述 \color{blue}{【思路】:} 好妙的一道最小生成树的题啊!

s u m i sum_i 表示前 i i 杯子的球的奇偶性的异或和,则区间 [ l , r ] [l,r] 内的所有球的奇偶性的异或和即为 s u m r sum_r 异或 s u m l 1 sum_{l-1} 的值。

把对区间 [ i , j ] [i,j] 的询问看着从 i 1 i-1 连一条边到 j j ,我们需要保证我们的询问没有环,而且需要 n n 次询问总花费最小。

想到了什么?对,没错,最小生成树,这就是最小生成树的典型应用!!!

理论上来说,因为输入是完全图,我们应该用Prim算法来做,但是因为笔者个人的习惯,代码中用了Kruskal算法。实测,效率在洛谷上还可以。

\color{blue}{【代码】:}

const int N=1e3+100;
struct union_set{
	int f[N],s[N];
	void init(int n){
		for(int i=0;i<=n;i++){
			f[i]=i;s[i]=1;
		}
	}
	int getf(int x){
		if (f[x]==x) return x;
		return f[x]=getf(f[x]);
	}
	void merge(int x,int y){
		int a=getf(x),b=getf(y);
		if (s[a]<s[b]) swap(a,b);
		if (a==b) return;//Remember it!!!
		f[b]=a;s[a]+=s[b];
	}
	bool query(int a,int b){
		return getf(a)==getf(b);
	}
}F;int n,tot;long long ans;
struct node{
	int u,v,cost;
	bool operator < (node c) const{
		return cost<c.cost;
	}
}e[N*(N+1)>>1];
int main(){
	freopen("t1.in","r",stdin);
	n=read();ans=0ll;tot=0;
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++)//注意是从i枚举到n
			e[++tot]=(node){i-1,j,read()};//注意从i-1连边到j
	sort(e+1,e+tot+1);F.init(n);
	for(int i=1,t=0;i<=tot;i++)
		if (!F.query(e[i].u,e[i].v)){
			F.merge(e[i].u,e[i].v);
			ans+=e[i].cost;t++;
			if (t==n) break;
		}
	cout<<ans;
	return 0;
}

\color{blue}{【关于代码】:}

  • 代码中的read()是快读函数,这里就不给出了。
  • union_set结构体即并查集,这是一个好习惯,即把数据结构封装到一个结构体中!!!
发布了103 篇原创文章 · 获赞 4 · 访问量 6735

猜你喜欢

转载自blog.csdn.net/ZHUYINGYE_123456/article/details/104173642