洛谷P1194 买礼物(Prim)

题目描述

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

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

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

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

输入格式

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

接下来BBB行,每行BBB个数,第III行第JJJ个为KI,JK_{I,J}KI,J

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

特别的,如果KI,J=0K_{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
只要想得到的话其实很简单。有优惠关系的两个点建边,求最小生成树后再加上一个a即可,看到数据范围跑Prim就行。
有几个重要的地方:
1.Kij可能大于a,因此建边要取min
2.要对Prim的模板稍微修改一下,忽略掉Kij=0的情况(没有优惠/i=j),因为没有优惠时Kij=0而非INF,不太符合一般认知2333
#include <bits/stdc++.h>
using namespace std;
int a,b,mmap[1005][1005],d[1005],ans=0;
bool v[1005];
void prim()
{
    memset(d,0x3f,sizeof(d));
    memset(v,0,sizeof(v));
    d[1]=0;
    int i,j;
    for(i=1;i<b;i++)
    {
        int x=0;
        for(j=1;j<=b;j++)
        {
            if(!v[j] &&  (x==0 || (d[j] && d[j] < d[x]) ) ) x = j;
        }
        v[x]=1;
        int y;
        for(y=1;y<=b;y++)
        {
            if(mmap[x][y]==0)continue;
            if(!v[y])d[y]=min(d[y],mmap[x][y]);
        }
    }
}
int main()
{
    cin>>a>>b;
    int i,j;
    for(i=1;i<=b;i++)
    {
        for(j=1;j<=b;j++)
        {
            scanf("%d",&mmap[i][j]);
            mmap[i][j]=min(mmap[i][j],a);
        }
    }
    prim();
    for(i=2;i<=b;i++)
    {
        ans+=d[i];
    }
    cout<<ans+a;
    return 0;
}


原文地址:https://www.cnblogs.com/lipoicyclic/p/12735460.html