1. 程式人生 > >[Luogu] P1195 口袋的天空

[Luogu] P1195 口袋的天空

cnblogs struct bool new ++ 圖論 span logs log

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; }

[Luogu] P1195 口袋的天空