题目描述
题目出处:点这里
输入格式
输出格式
样例
输入一
1 1
0
输出一
1
输入二
3 3
0 2 4
2 0 2
4 2 0
输出二
7
提示
样例二说明
样例规模
分析与思路
如果我们把有优惠关系的两个商品作为顶点,优惠后花掉的钱作为边权构建一个图,不难发现,我只需要找出在图中的最小生成树,即可得出本题的解,运用Keruskal算法就可以轻松解决这个问题
但是,先不要着急做,因为在这道题中,有两个没有描述清楚的坑:优惠后的价格不一定比原价便宜,按照优惠价格购买不一定比全用原价购买便宜,在做题的过程中需要特别注意
在注意到这两个坑后,我们就可以开始着手解决这个问题了
代码实现
#include<bits/stdc++.h>
using namespace std;
const int MXV=0x3f3f3f3f;
const int MXN=250000;
int n,m;
int k,p=0;
struct Node{
int n1,n2,w;
Node(){}
Node(int i,int d,int l){
n1=i;n2=d;w=l;
}
friend bool operator < (Node a,Node b){
return a.w<b.w;
}
};
Node edges[250000];
bool flag[MXN+1];
int mf[MXN+5];
int num=0;
int find(int v){
if(v==mf[v]){
return v;
}else{
return find(mf[v]);
}
}
void Keruskal(){
sort(edges+1,edges+1+p);
for(int i=1;i<=m;i++)mf[i]=i;
int esum=0;
for(int i=1;i<=p;i++){
int t1=find(edges[i].n1);
int t2=find(edges[i].n2);
if(t1==t2)continue;
mf[t2]=t1;
num+=min(n,edges[i].w);//优惠价可能比原价贵
esum++;
if(esum==m-1)break;
}
}
int main(){
cin>>n>>m;
int wsum=n*m;//记录全按照原价购买的所需金额
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
cin>>k;
if(k==0)k=n;//把没有优惠的按照原价处理
p++;
edges[p].n1=i;
edges[p].n2=j;
edges[p].w=k;
}
}
Keruskal();
for(int i=1;i<=m;i++){
if(i==mf[i]){//如果有没有出现在最小生成树(无优惠)里的商品,按原价购买
num+=n;
}
}
cout<<min(wsum,num);//与按优惠价购买的最比较
return 0;
}