洛谷 P1194 买礼物(最小生成树) 题解

题目来源:

https://www.luogu.org/problemnew/show/P1194

题目描述:

题目描述

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

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

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

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

输入输出格式

输入格式:

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

接下来BB行,每行BB个数,第II行第JJ个为K_{I,J}KI,J​。

我们保证K_{I,J}=K_{J,I}KI,J​=KJ,I​并且K_{I,I}=0KI,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

说明

样例解释22

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

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

数据规模

对于30\%30%的数据,1 \le B \le 101≤B≤10。

对于100\%100%的数据,1 \le B \le 500,0 \le A,K_{I,J} \le 10001≤B≤500,0≤A,KI,J​≤1000。

2018.7.25新添数据一组

解题思路:

       这题可以看出来,要买所有的物品,把物品看做点,优惠看做边,然后建边,求一次最小生成树再加上第一件的A元就行了,但是打了半天就只有90分,记得还有判断优惠的价格可能比A大,所以在读入的时候得判断一下

代码:

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <iomanip>
const int maxn=510;
using namespace std;
int tu[maxn][maxn],n,m,fa[maxn];
struct newt
{
    int from,to,cost;
}e[maxn*maxn];
bool cmp(newt a,newt b)
{
    return a.cost<b.cost;
}
int fi(int x)
{
    if(x==fa[x])return x;
    return fa[x]=fi(fa[x]);
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    scanf("%d",&tu[i][j]);
    int cnt=0;
    for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
    if(tu[i][j])
    {
        e[cnt].from=i;
        e[cnt].to=j;
        e[cnt++].cost=min(tu[i][j],m);
    }
    sort(e,e+cnt,cmp);
    for(int i=0;i<=n;i++)fa[i]=i;
    int ans=0;
    for(int i=0;i<cnt;i++)
    {
        int f1=fi(e[i].from),f2=fi(e[i].to);
        if(f1==f2)continue;
        fa[f1]=f2;
        ans+=e[i].cost;
    }
    for(int i=1;i<=n;i++)if(fa[i]==i)ans+=m;
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40400202/article/details/82355202