洛谷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
0

输入样例2

3 3
0 2 4
2 0 2
4 2 0

输出样例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。
n个物品都要买,就相当于把n个物品间接连通,又要用最小的代价,于是就可以拿最小生成树搞一搞。
代码如下

#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int size = 2000100;
int f[size];
int find(int x)
{
    if(f[x] == x)
        return x;
    return f[x] = find(f[x]);
}
int a,b;
LL tot = 0;
struct dc
{
    int f,t,d;
}l[size];
bool cmp(dc a,dc b)
{
    return a.d < b.d;
}
int main()
{
    scanf("%d%d",&a,&b);
    for(int i = 1 ; i <= b ; i ++)
    {
        for(int j = 1 ; j <= b ; j ++)
        {
            int in;
            scanf("%d",&in);
            if(in)
            {
                tot ++;
                l[tot].f = i , l[tot].t = j , l[tot].d = in;
            }
        }
    }
    sort(l+1,l+tot+1,cmp);
    for(int i = 1 ; i <= b ; i ++)
        f[i] = i;
    LL ans = 0;
    for(int i = 1 ; i <= tot ; i ++)
    {
        int ff = find(l[i].f) , ft = find(l[i].t);
        if(ff != ft)
        {
            f[ff] = ft;
            ans += l[i].d;
        }
    }
    for(int i = 1 ; i <= b ; i ++)
        if(f[i] == i)
            ans += a;
    printf("%lld\n",ans);
    return 0;
} 

你可能感兴趣的:(题解,图论,最小生成树)