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\),那么表示这两样东西之间不会导致优惠。

注意 \(K_{I,J}\) 可能大于 \(A\)

输出格式

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

输入输出样例 #1

输入 #1

1 1
0

输出 #1

1

输入输出样例 #2

输入 #2

3 3
0 2 4
2 0 2
4 2 0

输出 #2

7

说明/提示

样例解释 \(2\)

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

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

数据规模

对于 \(30\%\) 的数据,\(1\le B\le 10\)

对于 \(100\%\) 的数据,\(1\le B\le500,0\le A,K_{I,J}\le1000\)

2018.7.25新添数据一组
这道题可以用kruskal,首先是建边,如果两个点有优惠,我们可以建一条边,但要注意优惠价可能更贵,这时候我们就需要储存原价作为边,如果两个点没有优惠,者需要建一条原价边,sum初始时要为a,因为买第一个物品
肯定吃不到优惠,每条边储存的的优惠后的价格

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=500+5;
const int M=1e6+5;
struct line{
    int x,y,z;
}l[M];
bool cmp(line l1,line l2){
    return l1.z<l2.z;
}
int cnt=0;
int ans=0;
int f[N];
int a,b;
int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}
void kruskal(){
    int sum=a;
    for(int i=1;i<=b;i++)f[i]=i;
    for(int i=1;i<=cnt;i++){
        int rootx=find(l[i].x);
        int rooty=find(l[i].y);
        if(rootx!=rooty)f[rootx]=rooty,sum+=l[i].z;
    }
    ans=min(ans,sum);
}
int main(){
    
    cin>>a>>b;
    ans=a*b;
    for(int i=1;i<=b;i++){
        for(int j=1;j<=b;j++){
            int dis;
            cin>>dis;
            if(dis)l[++cnt].x=i,l[cnt].y=j,l[cnt].z=min(dis,a);
            if(i!=j&&!dis)l[++cnt].x=i,l[cnt].y=j,l[cnt].z=a;
        }
    }
    sort(l+1,l+1+cnt,cmp);
    kruskal();
    cout<<ans;
    return 0;
}
posted @ 2025-03-09 19:57  郭轩均  阅读(19)  评论(0)    收藏  举报