P1194 买礼物(建模)

 P1194 买礼物

题目描述

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

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

如果你买了第I样东西,再买第J样,那么就可以只花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]=0,那么表示这两样东西之间不会导致优惠。

输出格式:

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

输入输出样例

输入样例#1:
【样例输入1】
1 1
0
【样例输入2】
3 3
0 2 4
2 0 2
4 2 0
输出样例#1:
【样例输出1】
1
【样例输出2】
7

说明

样例解释2

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

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

数据规模

对于30%的数据,1<=B<=10。

对于100%的数据,1<=B<=500,0<=A,K[I,J]<=1000。

分析

首先建模,发现这是求最小生成树,可以用kruskal算法,但是如果只买一个时生成树不能求,所以最后扫一遍fa数组,加上n

代码

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 struct Edge{
 7     int u,v,w;
 8     bool operator < (const Edge &a) const 
 9     {
10         return w < a.w ;
11     }
12 }e[250100];
13 int n,m,k,ans,cnt;
14 int fa[5100];
15 
16 int find(int x)
17 {
18     return x==fa[x]?x:fa[x] = find(fa[x]);
19 }
20 int main()
21 {
22     scanf("%d%d",&n,&m);
23     for (int i=1; i<=m; ++i)
24         fa[i] = i;
25     for (int i=1; i<=m; ++i)
26         for (int a,j=1; j<=m; ++j)
27         {
28             scanf("%d",&a);
29             if (a==0) continue ;
30             e[++cnt].u = i;e[cnt].v = j;e[cnt].w = a;
31         }
32     sort(e+1,e+cnt+1);
33     for (int i=1; i<=cnt; ++i)
34     {
35         int rx = find(e[i].u);
36         int ry = find(e[i].v);
37         if (rx==ry) continue ;
38         fa[rx] = fa[ry];
39         ans += e[i].w;
40         if (k==m-1) break;
41     }
42     for (int i=1; i<=m; ++i) 
43         if (i==fa[i]) ans += n;
44     printf("%d",ans);
45     return 0;
46 }
原文地址:https://www.cnblogs.com/mjtcn/p/7168268.html