首页 > 技术文章 > 洛谷 P1194 买礼物 题解

acioi 2019-10-14 20:10 原文

P1194 买礼物

题目描述

又到了一年一度的明明生日了,明明想要买\(B\)样东西,巧的是,这\(B\)样东西价格都是\(A\)元。

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

如果你买了第II样东西,再买第JJ样,那么就可以只花\(K_{I,J}\)元,更巧的是,\(K_{I,J}\)​竟然等于\(K_{J,I}\)

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

输入格式

第一行两个整数,\(A,B\)

接下来\(B\)行,每行\(B\)个数,第\(I\)行第\(J\)个为\(K_{I,J}\)​。

我们保证\(K_{I,J}=K_{J,I}\)​并且\(K_{I,I}=0\)

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

输出格式

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

输入输出样例

输入 #1

1 1
0

输出 #1

1

输入 #2

3 3
0 2 4
2 0 2
4 2 0

输出 #2

7

说明/提示

样例解释\(2\)

先买第\(2\)样东西,花费\(3\)元,接下来因为优惠,买\(1,3\)样都只要\(2\)元,共\(7\)元。

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

数据规模

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

对于\(100\%\)的数据,\(1 \le B \le 500,0 \le A,K_{I,J} \le 1000\)

2018.7.25新添数据一组

【思路】

最小生成树(克鲁斯卡尔) + 并查集
很有意思
在买了一个东西之后买另一个东西会有不同的价格
这就可以看成建立一颗最小生成树
然后跑就可以了

不过这道题显然没有那么简单的
不然就真成为了一道克鲁斯卡尔板子题了
还需要考虑一个东西
不需要很大的思维了只是要细心
第一个买的东西是不是需要钱?
这是必然需要的
所以ans可以一开始就赋值为aa的价格

注意:

输入0就表示输入的原价购买没有优惠!

【完整代码】

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;
const int Max = 505;
struct node
{
	int x,y;
	int w;
}a[Max * Max]; 
int father[Max << 1];
bool cmp(const node x,const node y)
{
	return x.w < y.w;
}

int find(int x)
{
	if(father[x] != x)father[x] = find(father[x]);
	return father[x];
}

void hebing(int x,int y)
{
	x = find(x);
	y = find(y);
	father[x] = y;
}

int main()
{
	int aa,b;
	cin >> aa >> b;
	int js = 0;
	int jj = 0;
	for(register int i = 1;i <= b;++ i)
		father[i] = i;
	for(register int i = 1;i <= b;++ i)
		for(register int j = 1;j <= b;++ j)
		{
			cin >> a[++ jj].w,a[jj].x = i,a[jj].y = j;
			if(a[jj].w == 0)a[jj].w = aa;
		}
	sort(a + 1,a + 1 + jj,cmp);
	int ans = aa;
	for(register int i = 1;i <= jj;++ i)
	{
		if(find(a[i].x) != find(a[i].y))
			hebing(a[i].x,a[i].y),js ++,ans += a[i].w;
	}
	cout << ans << endl;
	return 0;
}

推荐阅读