• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
MZQ667
博客园    首页    新随笔    联系   管理    订阅  订阅

[Luogu] P1195 口袋的天空

Luogu P1195 口袋的天空


传送门

这个题因为提到\(N\)个棉花糖,\(M\)个关系,\(L\)的代价之类,所以可以想到有关图论。因为提到连成\(K\)个棉花糖,并且代价最小,所以可以想到将\(N\)个点变为\(K\)棵树。所以,本题解为跑最小生成树,还剩\(K\)个点(相当于\(K\)棵树)时停下,即得结果。

  1. Q: 为什么是树呢?

    A : 首先,如果\(K > N\),那么'No Answer';其次,如果\(K \leqslant N\),那么如果把一棵树连成了一个有环图,那么这个操作非但没有对增加棉花糖数量有所贡献,反而还增加了不必要的代价。

  2. Q : 为什么要跑最小生成树?

    A : 因为最小生成树每一步选边都保证了当前两点之间边权最小;且若将\(N\)个节点视作\(N\)棵树,每一步都会使树的总数减一;所以跑一个最小生成树即可解决。

跑了一个\(Kruskal\)。

#include <algorithm>
#include <cstdio>

const int MAXN = 1001;
const int MAXM = 10001;

struct EDGE{
    int v, u, w;
    bool operator < (const EDGE &a) const {
        return w < a.w;
    }
}edge[MAXM];

int n, m, k, tu, tv, tw, tot, ans;
int f[MAXN];

inline void U_init() {
    for (int i = 1; i <= n; ++i) f[i] = i;
    return ;
}
inline int find(int x) {
    if(f[x] != x) f[x] = find(f[x]);
    return f[x];
}
inline bool unionn(int x, int y) {
    int xx = find(x), yy = find(y);
    bool su = false;
    if(xx != yy) f[yy] = xx, su = true;
    return su;
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    if(n == k) {printf("%d\n", 0);}
    U_init();
    for (int i = 1; i <= m; ++i) 
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
    std::sort(edge + 1, edge + m + 1);
    tot = n;
    for (int i = 1; i <= m; ++i)
        if(unionn(edge[i].u, edge[i].v)) {
            ans = ans + edge[i].w;
            tot--;
            if(tot == k) break;
        }
    if(tot > k) printf("No Answer\n");
    else printf("%d\n", ans);
    return 0;
}
知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
posted @ 2018-03-09 21:28  mzq667  阅读(187)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3