洛谷P1194-买礼物

99 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

买礼物

题目描述

又到了一年一度的明明生日了,明明想要买 BB 样东西,巧的是,这 BB 样东西价格都是 AA 元。

但是,商店老板说最近有促销活动,也就是:

如果你买了第 II 样东西,再买第 JJ 样,那么就可以只花 KI,JK_{I,J} 元,更巧的是,KI,JK_{I,J} 竟然等于 KJ,IK_{J,I}

现在明明想知道,他最少要花多少钱。

输入格式

第一行两个整数,A,BA,B

接下来 BB 行,每行 BB 个数,第 II 行第 JJ 个为 KI,JK_{I,J}

我们保证 KI,J=KJ,IK_{I,J}=K_{J,I} 并且 KI,I=0K_{I,I}=0

特别的,如果 KI,J=0K_{I,J}=0,那么表示这两样东西之间不会导致优惠。

输出格式

一个整数,为最小要花的钱数。

样例 #1

样例输入 #1

1 1
0

样例输出 #1

1

样例 #2

样例输入 #2

3 3
0 2 4
2 0 2
4 2 0

样例输出 #2

7

提示

样例解释 22

先买第 22 样东西,花费 33 元,接下来因为优惠,买 1,31,3 样都只要 22 元,共 77 元。

(同时满足多个“优惠”的时候,聪明的明明当然不会选择用 44 元买剩下那件,而选择用 22 元。)

数据规模

对于 30%30\% 的数据,1B101\le B\le 10

对于 100%100\% 的数据,1B500,0A,KI,J10001\le B\le500,0\le A,K_{I,J}\le1000

2018.7.25新添数据一组

分析

这题是个最小生成树的题目,但是这题与我之前做过的那个昂贵的聘礼有异曲同工之妙,就是可以引入一个超级源点给每条边连一下,然后最小生成树克鲁斯卡尔大功告成!

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int a,b,res=0,fa[N];
struct pi{
	int a,b,w;
}edge[N];
bool cmp(pi x,pi y){
	return x.w<y.w?1:0;
}
int find(int x){
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
int main(){
	cin>>a>>b;
	int k=0;
	for(int i=0;i<=b;i++){
		fa[i]=i;
	}
	for(int i=1;i<=b;i++){
		for(int j=1;j<=b;j++){
			int w;
			cin>>w;
			if(i!=j && w!=0)
			edge[++k]={i,j,w};
		}
	}
	for(int i=1;i<=b;i++){
		edge[++k]={0,i,a};
		edge[++k]={i,0,a};
	}
	sort(edge+1,edge+k+1,cmp); 
	for(int i=1;i<=k;i++){
		int a=edge[i].a,b=edge[i].b,w=edge[i].w;
		int x=find(a),y=find(b);
		if(x!=y){
			res+=w;
			fa[x]=y;
		}
	}
	cout<<res<<endl;
} 

希望能帮助到大家(QAQQAQ)!