洛谷 P1194 买礼物 (题解+代码)

题目传送门:https://www.luogu.com.cn/problem/P1194
题解: 由于所有东西的价格都为a,并且买个第I个,再买第J个只需要话Kij。那么可以建立最小生成树,连接所有的边,然后再加个起点的值即可
需要注意的是: 优惠不一定比原价便宜!!!

代码及注释如下:

#include
#include
#include
using namespace std;
const int MAXN = 505;
struct node{
    int u,v,w;
    friend bool operator < (node a,node b) {
        return a.w < b.w;//优先小的
    }
}a[MAXN*MAXN];
int dis[MAXN];//记录祖先
int getf(int p) {//寻找p的祖先,路径压缩
    return dis[p]==p?p:dis[p]=getf(dis[p]);
}
int main() {
    int n,m,cnt = 0;//cnt记录边数
    cin>>n>>m;
    for(int i = 1;i <= m;i++) {
        for(int j = 1;j <= m;j++) {
            int tmp;
            cin>>tmp;
            if(i<=j) continue;//只需要记录一半的边即可(无向边只需要记录一条
            if(tmp==0) continue;//跳过无优惠的边
            a[++cnt] = {i,j,tmp};//存边
        }
        dis[i] = i;//初始化祖先为本身
    }
    sort(a+1,a+cnt+1);//排序
    int ans = n;
    for(int i = 1;i <= cnt;i++) {//总共只有cnt个边
        node tmp = a[i];
        if(getf(tmp.u)!=getf(tmp.v)) {//若还未在生成树中,则连接
            ans += tmp.w;
            dis[getf(tmp.u)] = dis[getf(tmp.v)];//向左结合
        }
    }
    cout<<min(n*m,ans);//生成树可能没有原价(n*m)便宜!!!
    return 0;
}

你可能感兴趣的:(#,最小生成树)