这道题如果看出题目实质就变得很简单了,不过看不穿的话就会很难想了。
大致思路如下:
第i件物品对j有优惠的话就建边,然后从0向各点连边权为a的边,然后跑一边kruskal就OK了。
***(易错误点)(本人):if(cnt==b)break;//****************这里b,不是b-1,因为我们这样计算会少购买一个物品,与以往的最小生成树不同(经过,两点之间的权边即可,但是这是购买全部‘点’)
#include<iostream>
#include<algorithm>
using namespace std;
struct edge{
int u,v,w;
}e[250000];
int fa[550],a,b,idx;
void add(int u,int v,int w)
{
e[++idx].u=u;
e[idx].v=v;
e[idx].w=w;
}
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
int find(int x)
{
if(fa[x]==x)return x;
else
{
fa[x]=find(fa[x]);
return fa[x];
}
}
int main()
{
cin>>a>>b;
for(int i=1;i<=b;i++)
for(int j=1;j<=b;j++)
{
int w=0;
cin>>w;
if(w!=0)
add(i,j,w);
}
for(int i=1;i<=b;i++)
{
add(0,i,a);
}
for(int i=1;i<=b;i++)
{
fa[i]=i;
}
sort(e+1,e+1+idx,cmp);
int sum=0,cnt=0;
for(int i=1;i<=idx;i++)
{
int f1=find(e[i].u);
int f2=find(e[i].v);
if(f1!=f2)
{
fa[f1]=f2;
sum+=e[i].w;
cnt++;
}
if(cnt==b)break;//****************这里b,不是b-1,因为我们这样计算会少购买一个物品,与以往的最小生成树不同(经过,两点之间的权边即可,但是这是购买全部‘点’)
}
cout<<sum<<endl;
return 0;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int u,v,w;
}e[250000];
int a,b,k,tot=1,ans,f[555];
bool cmp(node x,node y)
{
return x.w<y.w;
}
int find(int x)
{
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
int hb(int x,int y)
{
int xx=find(x);
int yy=find(y);
if(xx!=yy) f[xx]=yy;
}
void build(int x,int y,int z)
{
k++;
e[k].u=x;
e[k].v=y;
e[k].w=z;
}
void kruskal()
{
int j=1;
while(j<=k&&tot<=b)
{
if(find(e[j].u)!=find(e[j].v))
{
tot++;
ans+=e[j].w;
hb(e[j].u,e[j].v);
//printf("%d->%d\n",e[j].u,e[j].v);
}
j++;
}
}
int main()
{
scanf("%d%d",&a,&b);
for(int i=1;i<=b;i++)
{
for(int j=1;j<=b;j++)
{
int x;
scanf("%d",&x);
if(i<j&&x!=0) build(i,j,x);//千万记得没有优惠是0,不建边(我在这儿WA了三次......)
}
}
for(int i=1;i<=b;i++) build(0,i,a);
for(int i=0;i<=b;i++) f[i]=i;
sort(e+1,e+k+1,cmp);
kruskal();
//for(int i=1;i<=k;i++)
//printf("%d->%d:%d\n",e[i].u,e[i].v,e[i].w);
printf("%d\n",ans);
return 0;
}