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 }